C/C++ 如何进行操作?编译器在头文件中找到原型的定义?
当我在头文件中声明一个函数,并将该函数的定义放在其他文件中时,编译器/链接器如何找到该定义?它是否系统地搜索其路径中的每个文件,或者是否有更优雅的解决方案?这几天一直困扰着我,一直找不到解释。
When I declare a function in a header file, and put the definition of that function in some other file, how does the compiler/linker find the definition? Does it systematically search every file in its path for it, or is there a more elegant solution? This has been bugging me for the past few days, and I've been unable to find an explanation for it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
编译器不会这样做,链接器会这样做。
虽然编译器一次处理一个源文件,但当调用链接器时,它会传递编译器生成的所有目标文件的名称以及用户希望链接的任何库。因此,链接器完全了解可能包含定义的文件集,并且只需要查找这些目标文件的符号表。除此之外,它不需要进行任何搜索。
例如,假设您有 foo.h 和 foo.c 定义和实现函数
foo()
,并且 bar.h 和 bar.c 定义和实现bar()
。假设bar
调用foo
,以便 bar.c 包含 foo.h。此编译分为三个步骤:第一行编译 foo.c,生成 foo.o。第二个编译 bar.c,生成 bar.o。此时,在目标文件bar.o中,
foo
是一个外部符号。第三行调用链接器,它将 foo.o 和 bar.o 链接到一个名为“program”的可执行文件中。当链接器处理 bar.o 时,它会看到未解析的外部符号foo
,因此它会在所有正在链接的其他目标文件(在本例中只是 foo.o)的符号表中查找并找到foo.o 中的foo
,并完成链接。对于库,这有点复杂,它们在命令行上出现的顺序可能很重要,具体取决于您的链接器,但通常是相同的原理。
The compiler doesn't do this, the linker does.
While the compiler works on one source file at a time, when the linker is invoked it is passed the names of all of the object files generated by the compiler, as well as any libraries that the user wishes to have linked in. Therefore, the linker has complete knowledge of the set of files that could potentially contain the definition, and it needs only to look in the symbol tables of those object files. It doesn't need to do any searching beyond that.
For example, say you have foo.h and foo.c defining and implementing function
foo()
, and bar.h and bar.c defining and implementingbar()
. Saybar
callsfoo
so that bar.c includes foo.h. There are three steps to this compilation:The first line compiles foo.c, producing foo.o. The second compiles bar.c, producing bar.o. At this point, in the object file bar.o,
foo
is an external symbol. The third line invokes the linker, which links together foo.o and bar.o into an executable called "program". When the linker processes bar.o, it sees the unresolved external symbolfoo
and so it looks in the symbol table of all of the other object files being linked (in this case just foo.o) and findsfoo
in foo.o, and completes the link.With libraries this is a bit more complicated, and the order that they appear on the command line can matter depending on your linker, but it's generally the same principle.
当您编译 .cpp 文件时,编译器会在 .obj 文件中输出两个表:一个它期望在外部定义的符号列表,以及一个在该文件中定义的符号列表。特定模块。
链接器获取编译器输出的所有 .obj 文件,然后(顾名思义)将它们全部链接在一起。因此,对于每个模块,它都会查看标记为“外部定义”的符号列表,并查看为这些符号提供的所有其他模块。
因此,它只会“搜索”您告诉它搜索的模块。
如果它在任何其他模块中找不到该符号,那么您就会收到“未定义的引用”错误。
When you compile a .cpp file, the compiler outputs two tables in the .obj file: a list of symbols that it expects to be defined externally, as well as a list of symbols that are defined in that particular module.
The linker takes all of the .obj files that were output by the compiler and then (as the name suggests) links them all together. So for each module, it looks at the list of symbols that are marked "defined externally" and looks through all of the other modules it was given for those symbols.
So it only ever "searches" the modules that you told it search in.
If it can't find the symbol in any of the other modules, that's when you get the "undefined reference" error.
假设您有一个 foo.cpp ,其中包含 #include foo.h 以及其他可能的包含内容。标头当然可以有自己的#include-s。
预处理器将从 foo.cpp 开始,解析 #includes 并读取标头内容。结果将是来自头文件和 foo.cpp 的文本“扁平化”。
然后编译器将处理该文本。如果变量/函数/等应该有
如果未找到标头中的某处声明,编译器将报告错误。
基本点是编译器必须查看 .cpp 和标头的所有声明。
Assume you have a foo.cpp with an #include foo.h and maybe other includes. Headers can of course have their own #include-s.
The preprocessor will start with the foo.cpp, parse the #includes and read the header content. The result will be text from the header files and foo.cpp "flattened".
The compiler will then work off that text. If a variable/function/etc should have
been declared somewhere in a header wasn't found, the compiler will report an error.
The basic point is the compiler has to see all its declarations as a result of the .cpp and headers.