可能重复:
Why #include <stdio.h> is not required to use printf()?
已在stdio.h中声明了printf
和scanf
。但即使没有它们,它们也可以工作,仅仅发出警告信息?这背后的理论是什么?
答案 0 :(得分:12)
在不声明函数的情况下调用函数将根据您给出的参数和假定的返回类型int
创建隐式声明。这使得它可以通过编译阶段,因为该函数可能存在于链接时间之前未知的其他地方 - C并不总是具有函数原型,因此这是为了向后兼容。 (在C ++中,这是一个错误,在C99 GCC发出警告。)
如果您查看printf
,scanf
,puts
等的手册页(至少在FreeBSD和Darwin上),说它来自“标准C库(libc,-lc)”。 GCC隐式链接标准C库。如果您使用-nostdlib
标记进行链接,则会收到您期望的“未定义符号”错误。
(事实上,当我关闭libc
时,我的GNU / Linux系统也抱怨缺少_start
,我的OpenBSD系统抱怨_start
,{{1 }和__guard
。)
答案 1 :(得分:6)
默认情况下,C编译器假定没有声明的函数返回int并且不检查函数的参数。它可以找到一个声明然后编译器将检查参数
答案 2 :(得分:1)
当您的编译器警告您时,您应该弄清楚这意味着什么,并解决问题。编译器警告您无效代码然后继续编译代码的事实意味着很少。
至于他们为什么工作,答案是“运气不好”。它似乎只适合你,但不能保证符合C标准。
答案 3 :(得分:1)
因为在C中你不必提供函数原型,所以传递参数的标准转换,因此如果传递相同类型的参数,它应该有效。
回到C的早期,那里根本没有原型,它们稍后会添加。
注意:这在C ++中是不同的,在C ++上调用没有原型的函数会导致编译错误。
答案 4 :(得分:1)
在C中,如果你没有声明一个函数,然后你仍然使用它,默认它返回类型int
。 (顺便提一下,这也是这些函数的返回类型。)此外,在过去的日子里(ANSI之前),我认为你是否在原型中为函数指定了参数的名称或类型并不重要。因此,即使您的案例printf()
被声明为int printf();
,您也可以传递参数,但不会抱怨。我不确定标准中是否有任何保证声明的函数将具有与int (*)(const char *, ...)
相同的调用约定,但对于大多数编译器我会猜测答案是肯定的。所以它奏效了。
请注意C ++的规则不同。如果您将代码编译为C ++,我猜是编译器不会接受它。
答案 5 :(得分:0)
我怀疑你正在使用的GCC编译器实际上“知道”了一些常用的函数,比如printf,并且有特殊的代码来处理它们。这允许它执行诸如检查printf的格式字符串之类的事情,这些字符串是C或C ++标准不需要的。