C/C++编译器如何在头文件中找到原型的定义?

Joe*_*oel 21 c c++ header forward-declaration

当我在头文件中声明一个函数,并将该函数的定义放在其他文件中时,编译器/链接器如何找到定义?它是否系统地搜索其路径中的每个文件,还是有更优雅的解决方案?这一天一直困扰着我,我一直无法找到解释.

Tyl*_*nry 25

编译器不会这样做,链接器会这样做.

虽然编译器一次只能处理一个源文件,但是当调用链接器时,它会传递编译器生成的所有目标文件的名称,以及用户希望链接的任何库.因此,链接器完全了解可能包含该定义的文件集,并且只需要查看这些目标文件的符号表.除此之外,它不需要进行任何搜索.

例如,假设您有foo.h和foo.c定义和实现函数foo(),以及bar.h和bar.c定义和实现bar().说bar调用,foo使bar.c包含foo.h. 这个编译有三个步骤:

gcc -c foo.c
gcc -c bar.c
gcc foo.o bar.o -o program
Run Code Online (Sandbox Code Playgroud)

第一行编译foo.c,生成foo.o. 第二个编译bar.c,生成bar.o. 此时,在目标文件bar.o中,foo是一个外部符号.第三行调用链接器,它将foo.o和bar.o链接到一个名为"program"的可执行文件中.当链接器处理bar.o时,它会看到未解析的外部符号foo,因此它在链接的所有其他目标文件的符号表中查找(在本例中只是foo.o)并foo在foo.o中查找,并完成链接.

使用库时,这有点复杂,它们在命令行中出现的顺序可能会取决于您的链接器,但它通常是相同的原则.

  • 很好的答案 - 值得补充的是,至少有一个库 - 标准C库 - *隐含地*包含在链接行中.因此,在这种情况下,它不仅会出现在`foo.o`中,还会出现在未解析符号的标准C库中. (7认同)
  • *和*,当与g ++链接时,默认情况下你也会得到-lstdc ++. (2认同)

Dea*_*ing 14

编译.cpp文件时,编译器会在.obj文件中输出两个表:它希望在外部定义的符号列表,以及在该特定模块中定义的符号列表.

链接器获取编译器输出的所有.obj文件,然后(顾名思义)它们全部链接在一起.因此,对于每个模块,它查看标记为"外部定义"的符号列表,并查看为这些符号指定的所有其他模块.

所以它只会"搜索"你告诉它搜索的模块.

如果它在任何其他模块中找不到符号,那么当您收到"未定义的引用"错误时.