错误?请详细说明。我搜索了该网站,发现了类似的问题,但找不到明确的答案。大多数答案都说过有关包含头文件的内容以消除警告,但我想知道这不是错误。
#1 楼
应该认为是错误。但是C是古老的语言,因此只是警告。使用
-Werror
(gcc)进行编译可解决此问题。 int f();
,这意味着该函数可以接收您提供的任何内容,并返回一个整数。如果这恰好足够接近(如果是printf
,则可以),那么一切就可以正常进行。在某些情况下(例如,函数实际上返回了一个指针,并且指针比ints大),这可能会引起真正的麻烦。在这些标准中,这是一个错误。但是,默认情况下,gcc
未实现这些标准,因此您仍然会收到警告。评论
您的回答是当场正确的,并且准确地说出了K&R所说的。感谢您的简洁解释。
–火箭筒
2012年2月7日在20:22
请注意,即使在允许隐式声明的日子里,它们仍然会为诸如printf之类的可变函数生成UB。
–R .. GitHub停止帮助ICE
2012-2-7 23:42
@R ..,原则上您是对的。实际上,大多数实现都处理具有给定n个参数的可变函数,就像具有n个参数的普通函数一样,因此一切正常。
–ugoren
2012年2月8日在5:35
这个答案是24年前的正确答案。今天错了。当前的C标准(C11)和广泛使用的前一个标准(C99)都明确禁止调用未声明的函数。
–user529758
2013年12月1日0:11在
@ugoren一个非常流行的编译器,clang默认为C99,而另一个非常重要的编译器gcc支持它。市场上唯一被广泛使用的编译器,Microsoft的MSVC,是唯一不支持C89的编译器。因此,“编译器不使用较新的标准”是不正确的。
–user529758
2013年12月1日上午8:36
#2 楼
隐式声明在C中无效。C99删除了此功能(在C89中存在)。
gcc
选择仅在默认情况下对-std=c99
发出警告,但编译器具有拒绝翻译此类程序的权利。评论
与此相关的是,-pedantic-errors将使GCC(或CLang)按照此处的标准运行,并拒绝编译(请参阅:发出错误并中止)。
– TimČas
2015年2月10日在20:12
#3 楼
为了使图片更完整,由于-Werror
对于gcc(和llvm)可能被认为过于“侵入性”,一种更精确的解决方案是使用以下选项仅将此警告转换为错误:>
请参阅使gcc警告变为错误? br />
评论
相反,只要使-Werror中令人讨厌的内容静音即可。
–安蒂·哈帕拉(Antti Haapala)
17 Mar 2 '17 at 11:57
#4 楼
C是一种非常底层的语言,因此它允许您创建几乎可以想到的任何合法对象(.o)文件。您应该将C视为基本修饰的汇编语言。特别地,C不需要在使用函数之前对其进行声明。如果您在未声明函数的情况下对其进行了声明,则该函数的使用将成为其(隐式)声明。在我刚刚运行的一个简单测试中,这仅是对诸如printf之类的内置库函数的警告(至少在GCC中如此),但对于随机函数,它将编译得很好。
当然,当您尝试链接并且找不到foo时,您会得到一个错误。
对于诸如printf之类的库函数,某些编译器会为其包含内置声明。因此他们可以执行一些基本的类型检查,因此,当隐式声明(使用时)与内置声明不匹配时,您会收到警告。
评论
知道gcc为什么要为诸如printf之类的“内置函数”这样做吗?我似乎可以很好地使用用户定义的功能。
–火箭筒
2012年2月7日在20:34
“特别是,C不需要在使用函数之前先声明它们。” -是的。 C89(允许这样做)不是当前标准。 C11是,并且C11或其过分流行的前身C99都不允许调用隐式声明的函数。
–user529758
2013年12月1日0:13在
#5 楼
由于历史原因,可以追溯到C的第一个版本,所以假定函数具有int function(int arg1, int arg2, int arg3, etc)
的隐式定义。相反,它传递参数是什么类型。因此它可能是int
或int
或double
。没有原型,编译器将传递任何大小的参数,被调用的函数最好使用正确的参数类型来接收它。有关更多详细信息,请查阅
char*
。#6 楼
隐式声明的函数既没有原型也没有定义,但是在代码中被调用。因此,编译器无法验证这是否是函数的预期用途(计数和参数类型是否匹配)。解决它的引用是在编译后,链接时(与所有其他全局符号一样)完成的,因此从技术上讲,跳过原型不是问题。假定程序员知道他正在做什么,这是在此前提下省略了提供原型的正式合同。
如果使用错误类型或计数的参数调用该函数,则可能会发生讨厌的错误。这种情况最有可能的表现是堆栈损坏。
如今,此功能似乎显得晦涩难懂,但在过去,这是减少头文件数量的一种方法,因此编译速度更快。
评论
需要引用。我没有将隐式声明包含为改善编译时间的功能。据我所知,C(从B)的早期演变始于没有类型,但只有int,因此了解有关函数的类型信息并不那么重要...
–R .. GitHub停止帮助ICE
2012-2-7 23:44
当您说“原型”时,您的意思是“声明”。有些声明不是原型。
– M.M
17年1月31日在1:52
评论
默认情况下,标准C库链接到内部版本中。例如,使用gcc,您必须将-nostdlib作为传递给编译的参数,以强制其不与libc链接。@tbert这就是链接器没有抱怨的原因,但是链接器对编译器使用C代码的作用几乎没有什么影响。
另请参见stackoverflow.com/questions/22500/…
我查找了K&R,它说如果在作用域中没有该函数的先前声明是可见的,则假定函数使用的第一个实例是具有返回类型int的声明,并且不假设该参数。感谢大家的投入。
C89,C90或C99中的所有功能是否都需要原型?