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.alibc.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 &lt; /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标准库中的函数定义在哪里?的主要内容,如果未能解决你的问题,请参考以下文章

《C程序设计语言》笔记 (十五) 参考手册7

如何确定某个函数在Linux内核代码中的位置

哪种算法用于计算 GNU C++ 标准库中的指数函数?

C++ 命名空间 (namespace)

c++ 标准库函数都有哪些?

无法访问 Windows 标准库中的定义