让我们拿这个代码示例
//header
struct A { };
struct B { };
struct C { };
extern C c;
//code
A myfunc(B&b){ A a; return a; }
void myfunc(B&b, C&c){}
C c;
让我们从代码部分开始逐行执行此操作。 当编译器看到第一个myfunc方法时,它不关心A或B,因为它的使用是内部的。每个c ++文件都会知道它需要什么,它返回什么。虽然两个重载中的每个都需要有一个名称,所以如何选择以及链接器如何知道哪个意味着什么? 接下来是C c;我曾经有过一个错误,因为链接器不会重新协调,因此允许我访问其他C ++文件中的C.这是因为cpp并不知道c是extern,我必须在标题中将其标记为extern才能成功链接。现在我不确定类类型是否与链接器和变量C有任何关系。我不知道RTTI将如何参与,但我知道C需要被其他文件看到。
链接器如何工作并命名为mangling等。
答案 0 :(得分:2)
我们首先需要了解编译结束和链接开始的位置。编译涉及获取编译单元(C或C ++源文件)并将其转换为目标文件。简单地说,这涉及为每个函数生成机器代码片段以及所有函数和静态(全局)变量的符号表。占位符用于编译单元在所述编译单元外部所需的任何符号。
然后,链接器负责加载所有目标文件,并使用实际地址(或与机器无关的代码的偏移量)解析所有占位符符号。它被放置在各种部分中,在加载可执行文件时,操作系统的动态加载程序可以读取这些部分。
所以具体细节。为了避免链接期间的错误,编译器要求您声明将由当前编译单元使用的所有外部符号。对于全局变量,必须使用extern
关键字,对于函数,这是可选的。
函数中定义的所有函数和全局变量都有外部链接(即可以由其他编译单元引用),除非使用static
关键字(或C ++中的未命名命名空间)声明。在C ++中,vtable也会有一个链接所需的符号。
现在在C ++中,由于函数可以重载,因此参数也是函数名称的一部分。由于机器代码只是地址和寄存器,因此需要在符号表中的函数名称中添加额外的信息。此额外参数信息以错位名称的形式出现,并确保链接器链接到重载函数的正确版本。
如果您真的对血腥细节感兴趣,请查看Linux上广泛使用的ELF file format (PDF)。 Windows具有不同的格式,但原则可以预期相同。 可以在here找到Itanuim(和ARM)平台上的名称修改。
答案 1 :(得分:0)