【问题标题】:C++ simple question about how the linker works [duplicate]关于链接器如何工作的 C++ 简单问题 [重复]
【发布时间】:2021-12-06 03:23:26
【问题描述】:

假设我有一个名为 main.h 的文件,其中我声明了一些函数

void func();

然后我有一个包含定义的文件 main.cpp。 最后我有一个名为 a.cpp 的文件,其中包含 main() 并且只运行所有这些函数但我也有一些像这样声明的变量:

string a = "t";
int b = 2;

现在我的问题是链接器会将所有这些组合成一个可执行文件,对吗?但我的意思是变量ab 它们与任何东西有联系吗?我的意思是他们已经有了正确的定义,并且所有这些代码都以某种方式组合到一个可执行文件中,对吗?那么可以公平地说链接器也只是组合了所有 3 个文件中的所有代码吗?它看到声明并为它们找到定义,但是对于这些变量和东西,它们实际上没有任何要链接的东西,所以链接器甚至对它们做任何事情吗?或者像我之前说的,链接器基本上将所有这些代码组合在一起是否正确?

【问题讨论】:

  • 大致:编译器将源文件编译为中间二进制文件(目标文件),每个 cpp 文件对应一个。为此,它使用头文件来了解代码其他部分的符号。 (细节:在模板/内联函数的情况下,也从这些头文件中获取源代码)。所以 func 会在 somefile.obj 中结束,而 a 和 b 会在 main.obj 中结束。然后链接器会将它们组合成一个可执行文件(或静态或动态可链接库)

标签: c++


【解决方案1】:

从语言的角度来看,这称为范围。全局范围内的函数和变量应遵守单一定义规则。这意味着它们可以在任何编译单元中声明,但必须在程序中只定义一次。

对于函数,没有正文的声明 (void func();) 不是定义,可以在所有编译单元中使用,即使在包含定义的编译单元中也是如此。

对于变量,您必须使用 extern 关键字 (extern int b;) 才能拥有不是定义的声明。

同样的规则也适用于命名作用域:在任何命名作用域内,函数和变量都应该遵守单一定义规则。


从链接器的角度来看,事情稍微复杂一些,因为函数不止一个名称:它还包含其返回和参数类型:int func(void);int func(int); 声明了两个不同的函数。常见的实现使用名称修饰来构建包含名称和类型以及可选范围的复杂符号。编译器填充一个符号表来声明符号是本地定义的还是应该由链接器解析,链接器为这些符号分配一个(物理或虚拟)地址以生成可执行文件。

【讨论】:

    【解决方案2】:

    首先,编译器编译所有源文件,然后链接器将所有目标文件链接成一个可执行文件

    然后,链接器检查另一个翻译单元中的全局变量函数声明的链接。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-19
      • 1970-01-01
      相关资源
      最近更新 更多