使用GCC编译C项目时采用了哪些默认库

我有简单的应用:

#include  int main( int argc, char ** argv ) { printf( "hello"); exit( 0 ); } 

当我用命令编译它时

 gcc -c count_words.c 

我有警告:

 warning: incompatible implicit declaration of built-in function 'exit' [enabled by default] exit( 0 ); 

我试图找到定义exit()函数的位置。 并发现它是在stdlib.h定义的。 但它不包含在我的项目中,并且在编译命令中没有定义其他库。

如果我错了,请纠正我,但看起来像gcc默认使用一些库。 什么是这些库,是否可以告诉gcc不包括它们?

为什么编译器对exit(0)不满意,假设它以某种方式包含stdlib.h作为默认值?

我们举个例子:

 #include  int main( int argc, char ** argv ) { printf("hello\n"); exit(56); } 

虽然我们在编译时收到警告:

 ~$ gcc test.c -o test test.c: In function 'main': test.c:6:5: warning: implicit declaration of function 'exit' [-Wimplicit-function-declaration] exit(56); ^ test.c:6:5: warning: incompatible implicit declaration of built-in function 'exit' test.c:6:5: note: include '' or provide a declaration of 'exit' 

无论如何,我认为你已经尝试运行它并确保它有效:

 ~$ ./test hello ~$ echo $? 56 

当他说: @Mat说得对:

你正在混淆包括标题和链接到库。 这是两件完全不同的事情

C编译器和链接器是完全独立的工具。 我们来看看吧。 实际上,这个程序依赖于标准的C库(如果没有将-nostdlib传递给编译器, -nostdlib所有程序)和一些系统库(如loader和vdso)。 您可以看到它:

 ~$ ldd test linux-vdso.so.1 (0x00007fff1b128000) libc.so.6 => /lib64/libc.so.6 (0x00007f804389f000) /lib64/ld-linux-x86-64.so.2 (0x0000557744537000) 

这三个库是任何程序的最小集合。 exit函数在我们的案例中在标准库或libc.so.6中定义。 现在让我们以详细模式查看编译过程。 您可以通过将-v--verbose选项传递给编译器来实现此目的:

 gcc test.c -o test --verbose 

如果您将执行此操作,您将找到以下行:

 #include <...> search starts here: /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include /usr/local/include /usr/include 

因此,编译知道在哪里搜索stdlib头文件,它开始搜索它以查找非本地函数的声明。 请注意,它仅搜索源代码文件中包含的头文件。 它可以在stdio.h找到printf声明,但无法找到exit声明。

完成此步骤后,编译开始将程序与库链接:

 /usr/libexec/gcc/x86_64-redhat-linux/5.3.1/collect2 ... -lc ... 

其中collect2是gcc util,它试图将你的程序与标准C库的lc链接起来。 请注意,该过程包括两个步骤:编译和链接。 这就是你的程序有效的原因。

此外, gcc支持-M选项,它将告诉您主文件的依赖关系。 因此,如果您将执行它,您将看到包括stdio.h但不是stdlib.h的头文件集:

 $ gcc -M test.c test.o: test.c /usr/include/stdc-predef.h /usr/include/stdio.h \ /usr/include/features.h /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ /usr/include/gnu/stubs-64.h \ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h \ /usr/include/bits/types.h /usr/include/bits/typesizes.h \ /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdarg.h \ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h 

或者甚至更好,尝试将-E选项传递给gcc

 $ gcc -E test.c 

你会在第一阶段 – 预处理阶段之后看到结果。 我认为这是了解为什么会收到此警告的最简单方法。

假设它以某种方式包含stdlib.h作为默认值?

它根本没有。 这不符合标准。

因此,当您使用exit ,它从未被声明,因此在使用时会有隐式声明。 但是,您在其他任何地方实现exit的事实只会在最终链接中成为问题。

现在,海湾合作委员会非常了解你即将遇到麻烦,所以它会警告你。

简单地说实际上包括stdlib.h你应该没问题。

有问题的“库”是来自gcc源代码树的gcc / builtins.def。

这不仅仅是一个头文件,它不提供您使用的声明。 但它有适当的原型来检查你的。

调用未声明的exit()会导致隐式声明,如下所示:

 int exit(int); 

搜索“c隐式声明”以获取血淋淋的细节。 在这种情况下,GCC从builtins.def有自己的exit()原型:

 void exit(int) __attribute__((nothrow,noreturn)); 

这些声明不匹配,这就是你被警告的内容。

您的代码使用警告而不是错误。 如果你添加

 #include  

然后再没有警告了;)