C标准库中的函数定义在哪里?
Posted
技术标签:
【中文标题】C标准库中的函数定义在哪里?【英文标题】:Where are the functions in the C standard library defined? 【发布时间】:2014-03-07 03:38:28 【问题描述】:我对源代码不感兴趣,我想知道 C 编译器 (GCC) 是如何实际找到函数的。比如,当预处理器看到我包含了stdio.h
,它会在哪里找到定义函数体的文件?
编辑
我也应该说我使用的是 Ubuntu 12.04,但如果有一个通用的答案,那也可以。
【问题讨论】:
编译器只需要头文件。然而,链接器需要对象或库文件。 相关:***.com/questions/11481154/… 【参考方案1】:gcc
带有(二进制)目标文件(不是 C 源文件),其中包含所有标准 C 函数的实现。当您使用gcc
将目标文件链接到可执行文件时,链接器自动包含实现标准库函数的目标文件。根据this thread,该标准目标文件可能被称为libc.a
或libc.so
。
假设您在程序中包含对printf
的调用。当链接器试图解析该调用应该去哪里时,它会在libc.a
中找到printf
的定义,并将你的函数调用指向那里。
查看http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html 并注意-nostdlib
和-nodefaultlibs
选项。您可以使用这些选项告诉gcc
的链接器不默认包含标准库目标文件。
【讨论】:
那么链接器是否每次都自动包含实现所有标准库函数的目标文件?如果是这样,那么将不同的函数与不同的头文件相关联有什么意义?如果它们都被包含在内? 目标文件被gcc
链接器使用。 头文件由编译器使用。编译器需要查看标头,因此它知道函数签名,因此 1) 可以对代码进行类型检查,以及 2) 可以生成正确的代码来传递参数和获取返回值。为什么他们不把 all 标准库函数的签名放在一个单独的头文件中?好吧,一方面,它不符合 C 标准,因为 C 标准实际上定义了标准头文件应该是什么。另一方面,它会使编译时间变慢。
另外,@Tyler,除非需要,否则链接器不包含来自静态库的目标文件。 .a 文件是独立对象模块的索引库,链接器将仅包含那些解析未定义符号的库(其中一些可能引用新的未定义符号,因此它将继续运行)。对于 .so,整个库将在运行时加载,因此不适用。【参考方案2】:
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
,并且您会在其中找到代码中使用的函数的定义。
【讨论】:
【参考方案3】:您的问题与 GCC 搜索头文件的位置有关。它搜索标准包含目录。您可能会发现this thread 很有用:
使用各种选项(例如 -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 <...> 搜索从这里开始:”这样的短语,后跟一个 目录列表。这些是您的标准包含搜索路径, 按搜索顺序。
【讨论】:
这与找到库的位置有些相切,但如果默认情况下在/some/path/include
中找到标头,则通常在 /some/path/lib
中找到这些库。【参考方案4】:
在 Linux 上,您的 libc
(或 C++ 的 libstdc++
)可能位于 /usr/lib
或 /usr/lib64
。这些是共享库,您可以修改LD_LIBRARY_PATH
变量以指定在哪些目录中搜索它们。一个实际的示例是您安装gcc 的本地副本,并且很可能会有更新标准库的版本而不是您的系统,因此您希望本地 gcc 以该版本启动,即export LD_LIBRARY_PATH=/home/user/local-install/gcc/lib64
【讨论】:
C 编译器不太可能需要 libstdc++。 @BrianDrummond:是的,可能是错字。我确定了答案。【参考方案5】:它查看由环境变量设置的库路径。
阅读更多:http://gcc.gnu.org/onlinedocs/cpp/Search-Path.html
【讨论】:
他没有问gcc
在哪里找到标准头文件。他在问它在哪里可以找到这些函数的实体。以上是关于C标准库中的函数定义在哪里?的主要内容,如果未能解决你的问题,请参考以下文章