声明头文件必不可少?

Man*_*anu 4 c

声明头文件必不可少?这段代码:

main()
{
  int i=100;

  printf("%d\n",i);
}
Run Code Online (Sandbox Code Playgroud)

似乎工作,我得到的输出是100.即使不使用stdio.h头文件.这怎么可能?

pax*_*blo 14

你不必包含头文件.它的目的是让编译器知道有关的所有信息stdio,但如果您的编译器是智能(或懒惰),则绝不是必需的.

应该包含它,因为它是一个很好的习惯 - 如果你不这样做,那么编译器就没有真正的方法来知道你是否违反规则,例如:

int main (void) {
    puts (7);       // should be a string.
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译没有问题,但在运行时正确地转储核心.将其更改为:

#include <stdio.h>
int main (void) {
    puts (7);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

将导致编译器警告您:

qq.c:3: warning: passing argument 1 of ‘puts’ makes pointer
                 from integer without a cast
Run Code Online (Sandbox Code Playgroud)

一个不错的编译器可能会警告你这一点,比如gcc知道printf应该是什么样的,即使没有标题:

qq.c:7: warning: incompatible implicit declaration of
                 built-in function ‘printf’
Run Code Online (Sandbox Code Playgroud)


gav*_*inb 9

这怎么可能?简而言之:三件运气.

这是可能的,因为一些编译器会对未声明的函数做出假设.具体而言,假设参数为int,并且还返回类型int.由于a int通常与a相同char*(取决于体系结构),因此您可以通过传递ints和字符串来逃避,因为正确的大小参数将被推入堆栈.

在您的示例中,由于printf未声明,因此假定它采用两个int参数,并且您在调用方面传递了a char*int"兼容".所以编译器耸耸肩并生成了一些应该是正确的代码.(它确实应该警告你一个未声明的功能.)

所以第一个好运是编译器的假设与实际函数兼容.

然后在链接器阶段,因为它printf是C标准库的一部分,编译器/链接器将自动在链接阶段包含它.由于printf符号确实在C stdlib中,链接器解析了符号,一切都很好.链接是第二块运气,作为一个功能,除标准库之外的任何地方都需要链接它的库.

最后,在运行时我们会看到你的第三块运气.编译器做了一个盲目的假设,该符号碰巧默认链接在一起.但是 - 在运行时,您可以轻松传递数据,从而导致应用程序崩溃.幸运的是,参数匹配,并且正确的事情最终发生了.这肯定并非总是如此,我敢说上面的内容可能在64位系统上失败了.

所以 - 回答原始问题,包含头文件真的很重要,因为如果它有效,那只能通过盲目的运气!