术语“函数的隐式声明”是什么意思?调用标准库函数而不包含适当的头文件会产生警告,如下所示:
int main(){
printf("How is this not an error?");
return 0;
}
如果不声明它是错误的话,不应该使用函数吗?请详细解释。我搜索了这个网站,发现了类似的问题,但找不到明确的答案。大多数答案都说包括头文件以摆脱警告,但我想知道这不是一个错误。
答案 0 :(得分:71)
应该被视为错误。但C是一种古老的语言,所以它只是一个警告
使用-Werror
(gcc)进行编译可以解决此问题。
当C找不到声明时,它会假定这个隐式声明:int f();
,这意味着函数可以接收你给它的任何东西,并返回一个整数。如果这恰好足够接近(如果是printf
,那就是),那么事情就可以了。在某些情况下(例如函数实际返回指针,指针大于整数),可能会造成真正的麻烦。
请注意,这已在较新的C标准(C99,C11)中修复。在这些标准中,这是一个错误。但是,gcc
默认情况下不会实现这些标准,因此您仍会收到警告。
答案 1 :(得分:19)
隐式声明在C中无效。
C99删除了此功能(存在于C89中)。
gcc
选择仅在-std=c99
默认情况下发出警告,但编译器有权拒绝翻译此类程序。
答案 2 :(得分:5)
C是一种非常低级的语言,因此它允许您创建几乎任何您可以想到的合法对象(.o)文件。你应该把C看作基本装扮的汇编语言。
特别是,C在使用之前不需要声明函数。如果在不声明函数的情况下调用函数,则函数的使用将成为它(隐式)声明。在我刚刚运行的一个简单测试中,这只是内置库函数(如printf)的警告(至少在GCC中),但对于随机函数,它将编译得很好。
当然,当你尝试链接时,它找不到foo,那么你会收到错误。
对于像printf这样的库函数,有些编译器包含内置的声明,因此可以进行一些基本的类型检查,所以当隐式声明(来自使用)与内置声明不匹配时,你会收到警告。
答案 3 :(得分:3)
由于历史原因可以追溯到C的第一个版本,因此假定函数具有int function(int arg1, int arg2, int arg3, etc)
的隐式定义。
编辑:不,我对int
的参数错了。相反,它传递参数的任何类型。因此,它可以是int
或double
或char*
。如果没有原型,编译器将传递参数的任何大小,并且被调用的函数最好使用正确的参数类型来接收它。
有关详细信息,请查看K&R C
。
答案 4 :(得分:3)
要完成图片,因为-Werror
可能也被认为是"入侵",对于gcc(和llvm),更精确的解决方案是转换只是使用选项
-Werror=implicit-function-declaration
请参阅Make one gcc warning an error?
关于-Werror
的一般用法:当然,建议使用无警告代码,但在某些开发阶段,它可能会减慢原型设计速度。
答案 5 :(得分:1)
隐式声明的函数既不具有原型也不具有定义,而是在代码中的某处调用。因此,编译器无法验证这是函数的预期用法(参数的计数和类型是否匹配)。在编译之后,在链接时(与所有其他全局符号一样)解析对它的引用,因此从技术上讲,跳过原型不是问题。
假设程序员知道他在做什么,这就是省略提供原型的正式合同的前提。
如果使用错误类型或计数的参数调用函数,则会发生令人讨厌的错误。最可能的表现是堆栈的损坏。
现在这个功能可能看起来很模糊,但在过去,这是一种减少包含的头文件数量的方法,因此编译速度更快。