为什么我们需要在 C 中使用函数之前声明它们?
Why do we need to declare functions before using them in C?
在 C99 中,如果函数在声明之前被调用,编译器将发出警告。例如,这将导致警告:
int sum(const int k) {
return accsum(k, 0);
}
int accsum(const int k, const int acc) {
if (k == 0) {
return acc;
} else {
return accsum(k-1, k + acc);
}
}
int main() {
int x = sum(3);
return 0;
}
我在谷歌搜索后看到的答案是需要声明,以便编译器可以检查参数类型以避免错误。但是为什么在sum内部调用accsum时,编译器不能在执行accsum之前先找到accsum的函数定义呢?
这只是 cicra 1970 C 的遗留物。
强制程序员在使用函数之前声明函数允许编译器一次性工作(即只读取一次代码)。
40 年前限制编译时间很重要。今天只是一个烦恼。
编辑:
当然你必须声明external函数原型,否则编译器无法知道哪些参数和return 值得期待。这与声明的顺序无关。
安全方便的做法是将未声明的外部函数视为错误,并使程序员免于在同一编译单元内前向声明原型。
至于允许使用非原型函数,这又是大约 1970 年的遗留问题。 C99 不再允许隐式声明,但您仍然可以使用 K&R 样式声明(没有参数参数规范的原型)。
我想这种危险的可能性是出于向上兼容性的原因而保留的。
实际上,在C语言中,函数并不需要在使用前声明。如果遇到调用函数的尝试,编译器会假定一个可变参数列表,并且函数returns int。
现代编译器对在看到声明之前尝试调用函数发出警告的原因是声明允许编译器检查参数是否属于预期类型。给定声明,如果参数与函数声明中的规范不匹配,编译器会发出警告或错误。这会捕获程序员的很大一部分错误。
至于为什么编译器不预先查找定义,有几个促成因素。首先,C 有单独的编译模型——不能保证在当前编译单元(即源文件)中可以找到函数定义。其次,它允许编译器一次完成工作,从而提高性能。第三,它确实鼓励程序员实际声明函数(例如在头文件中),以允许在单独的编译模型中重用。第四,它增加了编译器实际能够在内存资源有限的机器上运行的机会。
在 C99 中,如果函数在声明之前被调用,编译器将发出警告。例如,这将导致警告:
int sum(const int k) {
return accsum(k, 0);
}
int accsum(const int k, const int acc) {
if (k == 0) {
return acc;
} else {
return accsum(k-1, k + acc);
}
}
int main() {
int x = sum(3);
return 0;
}
我在谷歌搜索后看到的答案是需要声明,以便编译器可以检查参数类型以避免错误。但是为什么在sum内部调用accsum时,编译器不能在执行accsum之前先找到accsum的函数定义呢?
这只是 cicra 1970 C 的遗留物。
强制程序员在使用函数之前声明函数允许编译器一次性工作(即只读取一次代码)。
40 年前限制编译时间很重要。今天只是一个烦恼。
编辑:
当然你必须声明external函数原型,否则编译器无法知道哪些参数和return 值得期待。这与声明的顺序无关。
安全方便的做法是将未声明的外部函数视为错误,并使程序员免于在同一编译单元内前向声明原型。
至于允许使用非原型函数,这又是大约 1970 年的遗留问题。 C99 不再允许隐式声明,但您仍然可以使用 K&R 样式声明(没有参数参数规范的原型)。
我想这种危险的可能性是出于向上兼容性的原因而保留的。
实际上,在C语言中,函数并不需要在使用前声明。如果遇到调用函数的尝试,编译器会假定一个可变参数列表,并且函数returns int。
现代编译器对在看到声明之前尝试调用函数发出警告的原因是声明允许编译器检查参数是否属于预期类型。给定声明,如果参数与函数声明中的规范不匹配,编译器会发出警告或错误。这会捕获程序员的很大一部分错误。
至于为什么编译器不预先查找定义,有几个促成因素。首先,C 有单独的编译模型——不能保证在当前编译单元(即源文件)中可以找到函数定义。其次,它允许编译器一次完成工作,从而提高性能。第三,它确实鼓励程序员实际声明函数(例如在头文件中),以允许在单独的编译模型中重用。第四,它增加了编译器实际能够在内存资源有限的机器上运行的机会。