编译器在何处找到“printf”

Where the compiler find ``printf``?

本文关键字:printf 在何处 编译器      更新时间:2023-10-16

我已经有一段时间没有接触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的实现?如果是,如何找到它们?

非常感谢!

如果您在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)

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

这是一个过于简单化的解释,没有提到内置程序、数学库等

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

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

短版本

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

长版本

头文件不包含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运行库中。这使得链接器可以很容易地找到