我对源代码不感兴趣,我想知道C编译器(GCC)实际上如何查找函数。例如,当预处理器看到我已经包含了
stdio.h
时,它会在哪里查找定义函数体的文件?
编辑
我应该还说一下,我正在使用Ubuntu 12.04,但如果有通用答案,那也可以。 stdio.h
时,它会在哪里查找定义函数体的文件?
编辑
我应该还说一下,我正在使用Ubuntu 12.04,但如果有通用答案,那也可以。gcc
带有(二进制)目标文件(不是 C源文件),其中包含所有标准C函数的实现。当您使用gcc
将目标文件链接成可执行文件时,链接器 自动地 包含了实现标准库函数的目标文件。根据此线程,标准目标文件可能称为libc.a
或libc.so
。
假设您的程序中包含对printf
的调用。当链接器尝试解析该调用应该去哪里时,它会在libc.a
中找到printf
的定义,并使您的函数调用指向那里。
查看http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html,并注意-nostdlib
和-nodefaultlibs
选项。您可以使用这些选项告诉gcc
的链接器默认情况下不包括标准库目标文件。
gcc
链接器使用。头文件由编译器使用。编译器需要看到头文件,以便了解函数签名,从而1)可以对代码进行类型检查,2)可以生成正确的代码以传递参数和获取返回值。为什么他们没有将所有标准库函数的签名放在单个头文件中?首先,这不符合C标准,因为C标准实际上定义了标准头文件应该是什么。另外,这会使编译时间变慢。 - Alex Dgcc
从 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
,并且您将在其中找到代码中使用的函数的定义。cpp -v < /dev/null
。这将使用没有输入的GNU C预处理器;在此过程中,它将打印(给定-v标志)包含目录搜索路径。您应该看到类似于“#include <...> search starts here:”的短语,后跟一个目录列表。这些是标准的包含搜索路径,按照它们被搜索的顺序。/some/path/include
中找到,则库通常在/some/path/lib
中找到。 - Jonathan Lefflerlibc
(或 C++ 的 libstdc++
)可能位于 Linux 上的 /usr/lib
或 /usr/lib64
中。这些是共享库,您可以修改 LD_LIBRARY_PATH
变量来指定它们要搜索的目录。一个实际的例子是,您安装了一个本地副本的 gcc,很有可能它会有一个更新版本的标准库,而不是您的系统,因此您希望您的本地 gcc 使用那个版本,即 export LD_LIBRARY_PATH=/home/user/local-install/gcc/lib64
。gcc
在哪里找到标准头文件。他想知道它在哪里找到这些函数的实现。 - Alex D