编译器在哪里找到“printf”?

Posted

技术标签:

【中文标题】编译器在哪里找到“printf”?【英文标题】:Where the compiler find ``printf``? 【发布时间】:2016-05-11 05:37:25 【问题描述】:

我已经有一段时间没有接触 c++了,这个问题可能很愚蠢,但它确实困扰了我一段时间。

假设我有以下 c 程序:

#include <stdio.h>

int main()

  int i;
  for(i=0; i<10; i++)
  
    printf("Hello World!\n");
  
  return 0;

我知道我包含stdio.h 的原因是因为我在main 中调用printf,但我想知道编译器如何知道在编译期间在哪里可以找到printf() 的实现? stdio.h 只提供函数原型,但编译过程中到底发生了什么?

是否存在编译器知道的某些前缀路径来搜索printf 的实现?如果有,如何找到它们?

非常感谢!

【问题讨论】:

真正找到它的是链接器。是的,查找标准库的路径是预定义的。 @πάνταῥεῖ 你能再解释一下吗?谢谢! Here's some more info "链接阶段的路径查找" 对于不同的编译器,或者对于同一个编译器的不同版本是不同的。你为什么对它感兴趣? 如果您想真正了解编译器/链接器正在寻找头文件和库(至少对于 gcc)的幕后情况,请参阅 ***.com/a/11481258/12711。 【参考方案1】:

如果您使用的是 linux 系统,则使用的 C 库可能是 glibc。 GCC 实际上并不提供 C 库实现,只提供头文件。实际实现这些函数的定义是 C 库的工作。在 Linux 上,有一种叫做“共享库”的东西,由需要它的程序动态加载。例如:

ldd /usr/bin/gcc
    linux-vdso.so.1 (0x00007ffd9e9f8000)
    libm.so.6 => /lib64/libm.so.6 (0x00007ff9a35a6000)
    libc.so.6 => /lib64/libc.so.6 (0x00007ff9a31de000)
    /lib64/ld-linux-x86-64.so.2 (0x000055953c573000)

您可以通过传递-nostdlib 并在您自己的C 库中链接来禁用libc 的链接。还有其他方法可以替换 C 库提供的定义,例如链接到您自己的 malloc 等。链接器只允许为任何给定的声明找到 一个 定义,并且由于 C 中没有名称修饰,因此很容易做到。

这是一个过于简单的解释,并没有提到内置函数、数学库等。

【讨论】:

【参考方案2】:

printf 是标准库的一部分,它被称为“标准”,因为它默认由 C 编译器链接。标准库通常由操作系统或编译器提供。在大多数 linux 系统上,它位于 libc.so,而在 MS Windows C 库上,由 Visual C 运行时文件 msvcrt.dll 提供。

【讨论】:

【参考方案3】:

经过一番挖掘,以下解释对我来说最有意义:

短版

头文件包含编译器需要的声明,但不包含实现。这 相应的库文件有那些。编译器需要头文件而不需要库;链接器 需要库,而不是头文件。

长版

头文件不包含printf()的定义 函数(即它的实现。)包含在 C 标准 I/O 库中(即glibc)。编译器无法创建机器指令 会导致 printf() 函数运行,因为它不知道在哪里 printf() 实施是; 它无法创建对此函数的调用。相反,编译器在可执行文件中放置一个符号 或多或少说,呼吁 printf() 必须由链接器解析。

链接器是在编译器之后运行的独立程序。它查看所有未解析的符号 程序,例如 printf() ,并尝试通过在软件库中查找它们的位置来解决它们 程序需要的。在这种情况下,链接器需要在 C 标准 I/O 库中查找位置 的 printf() 函数,以便它可以修补代码以调用它(ldd /usr/bin/gcc 方式或gcc -v foo.c -Wl --verbose 方式)。 C 标准 I/O 库 之所以特别,是因为它几乎用于每个 C 程序,因此许多 C 实现都包含它 在 C 运行时库中。这使得链接器可以轻松找到它

【讨论】:

以上是关于编译器在哪里找到“printf”?的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript 在哪里找到它的变量声明?

如何在编译期间指示 Emscripten 应该在哪里找到源文件?

反编译flutter release apk。在哪里可以找到源代码?

在哪里可以找到带有 -static 选项的 macOS 的预编译 Qt?

在哪里可以找到适用于 Android 的 nm 工具(已编译或源代码)

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