我写了#34;你好世界" C节目。
void main()
{ printf("Hello World"); }
// note that I haven't included any header file
该程序编译时带有警告
vikram@vikram-Studio-XPS-1645:~$ gcc hello.c
hello.c: In function ‘main’:
hello.c:2:2: warning: incompatible implicit declaration of built-in function ‘printf’
vikram@vikram-Studio-XPS-1645:~$ ./a.out
Hello Worldvikram@vikram-Studio-XPS-1645:~$
这怎么可能?操作系统如何在不包含任何标题的情况下链接库?
答案 0 :(得分:7)
printf
函数位于C库中(在您的情况下为libc
),它是隐式链接的(实际上gcc有一个内置的printf,但它在点之外)。
包含头文件不会为链接器带来任何函数,它只是通知编译器它们的声明(即“它们看起来像”)。
显然你应该总是包含头文件,否则你会强迫编译器假设函数是什么样的。
答案 1 :(得分:6)
编译器使用对名为printf()
,的函数的引用构建源文件,而知道它实际需要什么参数或返回类型是什么。生成的程序集在程序的静态数据区域中包含push
字符串"Hello World"
的地址,后跟call
到printf
。
将目标文件链接到可执行文件时,链接器会看到对printf
的引用,并提供C标准库函数printf()
。通过巧合,您传递的参数(const char*
)与真实printf()
的声明兼容,因此它可以正常运行。但请注意,您的程序隐式声明的printf()
返回类型int
(我认为),标准printf()
也有;但如果它们不同,并且您要将调用printf()
的结果分配给变量,那么您将处于未定义行为的范围内,并且您可能会得到不正确的值。
长话短说:#include
正确的标题可以为您使用的函数获取正确的声明,因为这种隐式声明已被弃用,因为它容易出错。
答案 2 :(得分:1)
在C中,如果使用标准库函数,则必须包含声明函数的标准头。对于printf
,您必须包含stdio.h
标头文件。
在C89(以及gcc
上默认为语言的GNU C89)中,有时可以省略函数声明,因为有一个称为隐式函数声明的特性:当函数标识符foo
是如果已使用且函数尚未声明,则实现将使用此声明:
/* foo is a function with an unspecified number of arguments */
extern int foo();
但是这个声明仅适用于返回带有未指定但固定个参数的int
的函数。如果函数接受可变数量的参数(如printf
),则此程序将调用未定义的行为。
这是C89 / C90所说的:
(C90,6.7.1)“如果定义了接受可变数量参数的函数而没有以省略号表示法结尾的参数类型列表,则行为未定义。
所以即使在C89和GNU C89中,gcc
也足够编译:编译器可以拒绝编译。
另请注意
void main() { ... }
不是main
的有效定义(至少在托管的实现上可能是你的情况)。
如果你的main函数没有接受任何参数,请使用这个有效的定义:
int main(void) { ... }
答案 3 :(得分:1)
标题通常 1 仅包含函数声明,符号常量和宏定义;它通常不包括函数定义。
所有stdio.h
都会为您提供printf
的原型声明:
int printf(const char * restrict format, ...); // as of C99
printf
的实现位于您的代码链接的单独库文件中。
您的代码“有效”有两个原因:
在C89及更早版本中,如果编译器看到函数调用
在该函数的声明或定义之前,它将假定
该函数返回int
并取一个未指定的数字
参数;
printf
的实现会返回int
,您就会传入
一个恰好恰好兼容的论点
printf
的实现需要第一个参数。
要回应其他人的说法,请使用int main(void)
或int main(int argc, char **argv)
;除非您的编译器文档显式将void main()
列为合法签名,否则使用它将调用未定义的行为(这意味着从运行时没有明显问题的代码到退出时崩溃到无法完全加载)。
答案 4 :(得分:0)
hello.c:2:2:警告:内置函数'printf'不兼容的隐式声明
要处理此警告,您应该包含头文件(stdio.h
)。您无意中使用了自1999年以来已弃用的旧C功能。
此外,链接不会失败的事实只是意味着默认情况下链接标准C库。您是否包含相关标题并不重要。