作者khoguan (Khoguan Phuann)
看板C_and_CPP
标题[FAQ集] 无标头档,直接呼叫 printf() 可以吗?
时间Thu Sep 1 23:39:15 2005
ptt.cc BBS 站 C_and_CPP 板 FAQ (0.1版)
函式语法
Q: 有一次我忘了 #include <stdio.h> 就呼叫 printf() 竟然也可以,何故?
A: 这是 C 比较不严谨的地方。 当我们呼叫一个函式 function_name()时,若
在呼叫处所在的范畴(scope)中,不存在相应的宣告,那麽 C 便会假定,包
含这个函式呼叫的最内层范畴中,存在这样的宣告:
extern int function_name();
对於这个隐式(implicit)的宣告,三点值得注意:
一、它具有外部连结。而且它的实际定义,存在於别处(也许编程者自己定
义在同一个原始码档的下方,也许存在於标准函式库中)。
二、它的传回值型别一律是 int。
三、它的参数未指定。(其後果参见上则)
所以如果我们在呼叫标准函式时,未能适当的引入标头档就直接呼叫。那麽
编译器就不再为我们根据标头档的函式宣告来做检查,也不会默默的替我们
去找标头档,只会根据上述的隐式宣告来编译这个源码档。最後在连结时,
连结器却会去标准函式库中硬生生的连结同名的函式。这样一来,即使我们
呼叫时传入的参数个数、型别,或是使用传回值的方式不合标准函式库那个
同名程式,一样会连结成功,产生一个不知会跑出什麽结果的可执行档。
例如:
int main()
{
int s = 0;
printf("s==%d\n", s); /* extern int printf() */
s = srand(1999); /* extern int srand() 和实际定义有出入 */
printf("s=="%d\n", s);
return 0;
}
其实 srand() 的传回型别是 void, 在这里却赋值给一个 int。因为没引入
标头档,编译器就失去为我们把关的能力。连结成功,执行的结果,在不同
系统上,会得到不同结果。
至於 C++ 在这方面就严谨多了,没有先明文宣告(包括引入合适的标头档),
是不能直接呼叫函式的。
呼叫一个并未明文宣告的函式是不良的 C 程式风格,更是错误的 C++ 程式。
结论就是,无论写 C 或 C++,都应该规规矩矩的,该 include 的就 include。
一时偷懒,要除错时就有得受了。
-----------------------------------
敬请指正错误,或提出更合适的答案。
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.130.208.167
1F:推 prudent:说的好~~ 顶一个... 220.142.39.22 09/02
※ 编辑: khoguan 来自: 220.130.208.167 (09/03 13:31)