例如:
Foo.cpp中:
extern int x; void f() { x = 42; } struct T { T() { f(); } } t; // we use constructor of global // object to call f during initialization
bar.cpp:
#include <iostream> int x; int main() { std::cout << x; }
要编译/链接/运行:
$g++ -c foo.cpp $g++ -c bar.cpp $g++ foo.o bar.o $./a.out 42
这似乎与gcc 4.7一起使用.它按预期输出42.但是我记得一些旧的编译器,我有一个这个模式的问题,因为没有什么是真正的“使用”foo.o它被优化在链接时间. (也许这个特定的例子不是由于某种原因代表问题)
C11标准对这种模式有什么看法?保证工作吗?
解决方法
您的对象t被动态初始化,这具有调用f的副作用.这个标准有关静态存储对象的动态初始化的说明(3.6.2 / 4,“非局部变量的初始化”):
It is implementation-defined whether the dynamic initialization of a non-local variable with static storage
duration is done before the first statement of main. If the initialization is deferred to some point in time
after the first statement of main,it shall occur before the first odr-use (3.2) of any function or variable
defined in the same translation unit as the variable to be initialized.
在你的代码中,只有x是odr使用的,但是x在主要的翻译单元中定义.程序中没有使用其他TU的变量或函数,所以在技术上不能保证t将被初始化.从技术上讲,每个TU的内容必须由程序的静态控制流程引用,以便初始化所有内容.
正如我所说,有很多真实世界的代码,有“自我注册”翻译单位(例如,在字符串键映射中注册一个工厂函数指针),以便通过简单地添加TU到最终的程序,你结束具有更多的功能.我被告知大多数编译器将无条件地初始化所有全局变量,因为不这样做会打破很多现实世界的代码.但不要依赖它!