C++ C++;11在链路上调用寄存器函数?
有没有办法通过链接函数的.o文件来调用函数 例如: foo.cpp:C++ C++;11在链路上调用寄存器函数?,c++,c++11,C++,C++11,有没有办法通过链接函数的.o文件来调用函数 例如: 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; i
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;
}
这似乎适用于GCC4.7。它按预期产出42项。然而,我记得在一些旧的编译器上,我对这种模式有一个问题,因为没有任何东西真正“使用”foo.o,它在链接时被优化了。(也许由于某种原因,这个特定的例子不能代表这个问题)
关于这个模式,C++11标准有什么说法?是否保证有效?相关章节为2.2[法律阶段]第1段第8项和第9项: .8。翻译单元和实例化单元的组合如下:[注:部分或全部可从库中提供。-结束注]检查每个翻译单元以生成所需实例化的列表。[注:这可能包括明确要求的实例化(14.7.2)。-结束注]所需模板的定义位于。是否需要提供包含这些定义的翻译单元的源是由实现定义的。[注:实现可以将足够的信息编码到翻译单元中,以确保此处不需要源代码。-结束注]执行所有必需的实例化以生成实例化单元。[注:这些类似于已翻译的翻译单元,但不包含对未实例化模板的引用,也不包含模板定义。-结束注]如果任何实例化失败,则程序格式错误 .9。解析所有外部实体引用。库组件被链接以满足对当前转换中未定义的实体的外部引用。所有这些转换器输出都被收集到一个程序映像中,该映像包含在其执行环境中执行所需的信息
第8项是我能找到的最好的一项,表明所有翻译单元都必须包括在内。第9项只是说明解析符号所需的一切也都被拉入。实际上,这意味着显式包含翻译单元具有预期效果。但是,将翻译单元放入库中并不能实现这一点。我想这就是你过去的经历:例如,将实现放入库中,并希望它们在启动时注册。由于相应的翻译单元中没有符号解析未引用的符号,因此库中的对象文件不会被拉入,相应地,全局对象也不会被初始化。我相信您还没有脱离困境。该标准并不保证您的代码按预期工作,尽管许多人依赖于这种行为进行各种“自注册”构造 对象
t
是动态初始化的,其副作用是调用f
。本标准对静态存储对象的动态初始化(3.6.2/4,“非局部变量的初始化”)作了如下说明:
它是实现定义是否动态初始化一个具有静态存储的非局部变量
持续时间在main的第一个语句之前完成。如果初始化延迟到某个时间点
在main的第一个语句之后,它应出现在任何函数或变量的第一次odr使用(3.2)之前
在与要初始化的变量相同的转换单元中定义
在您的代码中,仅使用了x
,但在主翻译单元中定义了x
。您的程序中没有使用来自另一个TU的变量或函数odr,因此技术上无法保证t
将被初始化。从技术上讲,为了初始化所有内容,程序的静态控制流必须引用来自每个TU的内容
正如我所说,现实世界中有很多代码都带有“自注册”翻译单元(例如,在字符串键控映射中注册工厂函数指针),因此,只需将TUs添加到最终程序中,就可以获得更多功能。我听说大多数编译器都会无条件地初始化所有全局变量,因为不这样做会破坏很多实际代码。但不要依赖它 该标准并没有真正说明如何选择翻译单元来组合成一个完整的程序,而且据我所知,在C++98和C++11之间,这方面没有什么重要的变化
实际上,当您将TU链接为
.o
时,无论发生什么,您都会得到它的静态初始值设定项,而如果您将它链接为.a
的一部分,则只有当TU中的其他内容从main()
或链接为.o
的另一个文件中被传递引用时,您才会得到它的静态初始值设定项ld
的--整个存档
标志覆盖此项,并将存档的每个成员拉入,就像您将其作为单个.o
列出一样。其他链接器可能会以不同的方式处理此问题。我认为这仍然是正确的:标准不要求在调用其翻译单元中的函数之前初始化t
。这是很难解释的,因此大多数编译器都会按照您的期望进行编译,但您需要知道的是,在这方面您没有标准的支持…@KerrekSB:标准中使用的术语是什么?或者标准的哪一部分解决了这个问题?@KerrekSB:你应该把你的评论作为一个答案,它值得投票对象不必使用odr:quote部分中的odr规则是对实现的限制,而不是对用户的限制。此外,本节讨论初始化顺序,而不是是否包括翻译单元及其局部变量。@DietmarKühl:如果不使用odr,则初始化t
$ g++ -c foo.cpp
$ g++ -c bar.cpp
$ g++ foo.o bar.o
$ ./a.out
42