C标准库中的函数定义在哪里?

20
我对源代码不感兴趣,我想知道C编译器(GCC)实际上如何查找函数。例如,当预处理器看到我已经包含了 stdio.h 时,它会在哪里查找定义函数体的文件? 编辑 我应该还说一下,我正在使用Ubuntu 12.04,但如果有通用答案,那也可以。

8
编译器只需要头文件,而链接器需要目标文件或库文件。 - Joey
相关:https://dev59.com/U2gu5IYBdhLWcg3wOUq- - Ciro Santilli OurBigBook.com
5个回答

26

gcc带有(二进制)目标文件(不是 C源文件),其中包含所有标准C函数的实现。当您使用gcc将目标文件链接成可执行文件时,链接器 自动地 包含了实现标准库函数的目标文件。根据此线程,标准目标文件可能称为libc.alibc.so

假设您的程序中包含对printf的调用。当链接器尝试解析该调用应该去哪里时,它会在libc.a中找到printf的定义,并使您的函数调用指向那里。

查看http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html,并注意-nostdlib-nodefaultlibs选项。您可以使用这些选项告诉gcc的链接器默认情况下包括标准库目标文件。


链接器是否每次自动包含实现所有标准库函数的目标文件?如果是这样,那么将不同的函数与不同的头文件关联有什么意义,如果它们都会被包含进来呢? - Tyler
目标文件gcc链接器使用。头文件编译器使用。编译器需要看到头文件,以便了解函数签名,从而1)可以对代码进行类型检查,2)可以生成正确的代码以传递参数和获取返回值。为什么他们没有将所有标准库函数的签名放在单个头文件中?首先,这不符合C标准,因为C标准实际上定义了标准头文件应该是什么。另外,这会使编译时间变慢。 - Alex D
此外,@Tyler,链接器不会包含静态库中不必要的目标文件。.a文件是一个索引库,包含了独立的目标模块,链接器只会包含那些解决未定义符号的模块(其中一些可能引用新的未定义符号,所以它会继续进行)。对于.so文件,整个库将在运行时加载,因此这不适用。 - greggo

13

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,并且您将在其中找到代码中使用的函数的定义。

4
您的问题与GCC搜索头文件的位置有关。它会搜索标准包含目录。您可能会发现这个线程很有用:
使用各种选项(例如-I和-I-和-isystem),您可以指定许多不同的包含特性。基本上,由-I指定的目录将在-isystem指定的目录之前被搜索,后者将在“标准系统包含目录”中搜索(至少根据我的测试)。区别在于-I可用于任何#include指令,但-isystem只能用于#include <...>。尽管如此,建议仅使用-I用于#include "..."指令,因为搜索顺序。使用-I-确实给您带来了很多控制权,因为在-I-之前使用的任何-I仅将用于#include "...",而在-I-之后使用的任何-I都将用于任何#include指令。此外,使用-I-意味着当前目录将不会搜索包含的文件,除非您还指定了-I。(搜索当前目录)。
如果想获取默认支持的搜索目录列表,请尝试运行此命令:cpp -v < /dev/null。这将使用没有输入的GNU C预处理器;在此过程中,它将打印(给定-v标志)包含目录搜索路径。您应该看到类似于“#include <...> search starts here:”的短语,后跟一个目录列表。这些是标准的包含搜索路径,按照它们被搜索的顺序。

1
这与库的位置有些不相关,但如果默认情况下标题文件在/some/path/include中找到,则库通常在/some/path/lib中找到。 - Jonathan Leffler

2
您的 libc (或 C++ 的 libstdc++)可能位于 Linux 上的 /usr/lib/usr/lib64 中。这些是共享库,您可以修改 LD_LIBRARY_PATH 变量来指定它们要搜索的目录。一个实际的例子是,您安装了一个本地副本的 gcc,很有可能它会有一个更新版本的标准库,而不是您的系统,因此您希望您的本地 gcc 使用那个版本,即 export LD_LIBRARY_PATH=/home/user/local-install/gcc/lib64

C编译器不太可能需要libstdc++库。 - user1818839
@BrianDrummond:是的,可能是打错了。我已经修正了答案。 - sleske

1

1
他并不是问gcc在哪里找到标准头文件。他想知道它在哪里找到这些函数的实现 - Alex D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接