为什么链接器不能阻止C++静态初始化命令惨败?

6 c++ linker

编辑: 将下面的示例更改为实际演示SIOF的示例.

我试图理解这个问题的所有细微之处,因为在我看来它是语言中的一个主要漏洞.我已经读过链接器无法阻止它,但为什么会这样呢?在简单的情况下防止这样做似乎微不足道:

// A.h
extern int x;

// A.cpp
#include <cstdlib>

int x = rand();

// B.cpp
#include "A.h"
#include <iostream>

int y = x;

int main()
{
    std::cout << y; // prints the random value (or garbage)?
}
Run Code Online (Sandbox Code Playgroud)

在这里,链接器应该能够容易地确定A.cpp的初始化代码应该在链接可执行文件中的B.cpp之前发生,因为B.cpp依赖于在A.cpp中定义的符号(并且链接器显然已经必须解决这个问题).

那么为什么不能将它推广到所有编译单元.如果链接器检测到循环依赖,不能只是失败,错误的链接(或者可能是一个警告,因为它可能是程序员的意图,我想定义在一个编译单元中的全局符号,而在另一个初始化) ?

标准是否对实现有任何要求以确保在简单情况下正确的初始化顺序?什么是不可能的情况的例子?

我知道在全球销毁时可能发生类似的情况.如果程序员没有仔细确保破坏期间的依赖关系与构造对称,则会出现类似的问题.链接器是否也不会对这种情况发出警告?

小智 6

传统上,链接器只是链接 - 即它们解析地址.您似乎希望他们对代码进行语义分析.但是他们无法访问语义信息 - 只有一堆目标代码.现代链接器至少可以处理大符号名称并丢弃重复符号以使模板更有用,但只要链接器和编译器是独立的,就是这样.当然,如果链接器和编译器都是由同一个团队开发的,并且如果该团队是一个大公司,那么可以在链接器中添加更多的智能,但是很难看出可移植语言的标准如何能够强制执行这样的事情.

如果你想了解更多关于链接器的信息,请看看http://www.iecc.com/linker/ - 关于经常被忽略的工具的唯一一本书.