我对源代码不感兴趣,我想知道C编译器(GCC)实际上是如何找到这些函数的。同样,当预处理器看到我已经包含stdio.h
时,它在哪里找到定义函数体的文件?
修改
我可能也应该说我正在使用Ubuntu 12.04,但如果有一般答案,那也可以。
答案 0 :(得分:23)
gcc
附带(二进制)目标文件(不是 C源文件),其中包含所有标准C函数的实现。使用gcc
将目标文件链接到可执行文件时,链接器自动包括实现标准库函数的目标文件。根据{{3}},该标准对象文件可能会被称为libc.a
或libc.so
。
假设您在程序中包含对printf
的调用。当链接器尝试解析该调用的位置时,它会在printf
中找到libc.a
的定义,并在那里调用函数调用点。
查看this thread并注意-nostdlib
和-nodefaultlibs
选项。您可以使用这些选项告诉gcc
的链接器不默认包含标准库对象文件。
答案 1 :(得分:12)
gcc
从C库获取函数定义。默认情况下,您可以通过以下方式确定gcc
将要查看的路径:
ld --verbose | grep SEARCH_DIR
这导致我的系统/usr/lib
。
让我们尝试查找该库是否包含标准函数的符号,例如scanf
:
nm -A /usr/lib/libc.so | grep scanf
结果包括:
/lib/libc.so:0000000000042a90 T scanf
考虑一个小例子:
#include <stdio.h>
int main() {
printf("Hello World!\n");
return 0;
}
让我们称之为i.c
:
$ gcc i.c # Compile
$ ldd ./a.out # Try to find dependencies
./a.out:
-lc.12 => /usr/lib/libc.so.12
最后一个命令实质上意味着二进制文件依赖于/usr/lib/libc.so.12
,并且您可以找到其中代码中使用的函数的定义。
答案 2 :(得分:4)
您的问题与GCC搜索头文件的位置有关。它搜索标准包含目录。您可能会发现this thread很有用:
您可以指定各种选项(例如-I和-I-和-isystem) 许多不同的包含功能。基本上,指定目录 by -I将在-isystem指定的那些之前进行搜索 反过来在标准系统中的那些之前进行搜索 目录&#34; (至少,根据我的测试)。不同之处在于 -I可以用于任何#include指令,但是--isystem只能用于#include&lt; ...&gt;虽然如此,但建议仅限于此 使用-I表示#include&#34; ...&#34;因搜索顺序而导致的指令。 使用-I-真的给你很多控制权,因为之前使用过的任何一个 -I-将只搜索#include&#34; ...&#34;而在-I-之后使用的任何-I将被搜索任何#include指令。此外, 使用-I-表示不会搜索当前目录 包含文件,除非您还指定-I。 (搜索当前 目录)。
如果您想获得支持哪些搜索目录的列表 默认情况下,尝试运行此命令:
cpp -v < /dev/null
此命令运行 没有输入的GNU C预处理器;在这个过程中它会打印出来 (给定-v标志)包含目录搜索路径。你应该 看到像&#34; #include&lt; ...&gt;这样的词组搜索从这里开始:&#34;接下来是 目录列表。这些是您的标准包含搜索路径, 按照他们搜索的顺序。
答案 3 :(得分:2)
您的libc
(或libstdc++
for C ++)可能位于Linux上的/usr/lib
或/usr/lib64
。这些是共享库,你可以修改LD_LIBRARY_PATH
变量来指定它们被搜索到的目录。一个实际的例子是你安装gcc的本地副本,它有可能会有与您的系统相对的标准库的更新版本,因此您希望本地gcc改为启动,即export LD_LIBRARY_PATH=/home/user/local-install/gcc/lib64
答案 4 :(得分:1)
它查看由环境变量设置的库路径。