跨C++文件和库对静态工具举办初始化
副标题#e#
假期凡是是个回首已往的好时候。这里就是我正在思考的上个月使我发生"ah-hah"瞬间的一个 问题。
问题:
当你编译下面的C++措施的时候,你大概认为模块(module)中的工具会先编译并先初始 化。
这种假设大概得不到预期的功效。
X.h :
#include <string>
using namespace std; // 译者注: 加上这行
class CObjet {
public:
static const string STRINGX;
};
X.cpp:
#include <X.h>
using namespace std; // 译者注: 这行可以不要
const string CObjet::STRINGX = "001";
Y.cpp:
#include <iostream>
#include <X.h>
const string STRINGY= CObjet::STRINGX;
int main () {
cout << "CObjet::STRINGX [" <<CObjet::STRINGX << "]" << endl;
cout << "STRINGY [" << STRINGY << "]" << endl;
return 0;
}
假如用下面的呼吁来编译:
xlC -c -I./ X.cpp -o X.o
xlC -c -I./ Y.cpp -o Y.o
xlC -o binary X.o Y.o
#p#副标题#e#
然后获得的功效如下:
./binary
CObjet::STRINGX [001]
STRINGY [] // 译者注: 该功效是AIX平台的, Linux平台大概会Segmentation fault
从这个功效来看,STRINGY并没有像预期的那样初始化为STRINGX
原因:
STRINGX和STRINGY是全 局静态工具。STRINGY的初始化取决于STRINGX的初始化。两者界说在差异的源文件中。
固然C++语言类型规 定了同一个文件中这类工具的初始化顺序(凭据界说的顺序),但并没有划定在跨文件可能库时这些工具的初始 化顺序。
因此固然模块X.o先编译, STRINGX仍大概会在STRINGY之后初始化, 这就形成了一个空的 STRINGY.
取决于编译器和操纵系统缓存中当前的值, STRINGY甚至大概包括了垃圾数据并导致措施运行时崩 溃。
办理方案:
为了办理这个问题,一些开拓者将每个非局部静态工具都移动到本身的函数中,并 声明为静态的。并让这些函数返回这个静态工具的引用, 然后凭据本身期望的工具初始化顺序来挪用这些函数 .固然这凡是是个可移植的要领,可是这需要修改代码。
XL C/C++编译器可以使得这项事情变得简朴。你可以利用-qpriority或-qmkshrobj=priority(译者注: linux上只有-qmkshrobj形式) 或 -Wm,-c选项来指定界说在差异文件可能库中的静态工具的初始化顺序。这些 选项会给每个模块赋予一个优先级值,然后按照该值来节制工具的初始化顺序。
包括主函数main()的模块凡是优先级为0. 值越小暗示优先级越高,在上面的例子中,可以在编译X.o的时候 指定-qpriority=-100从而担保X.o中的工具在Y.o工具初始化之前初始化。
同样的,假如你想把X.o建设到一个共享库中,那么可以在建设该库的时候指定-qmkshrobj=-100。
即,你可以用下面的呼吁来编译:
xlC -c -I./ -qpriority=-100 X.cpp -o X.o
xlC -c -I./ Y.cpp -o Y.o
xlC -o binary X.o Y.o
可能, 建设共享库:
xlC -c -I./ X.cpp -o X.o
xlC -c -I./ Y.cpp -o Y.o
xlC -qmkshrobj=-100 -o libX.so X.o
xlC -o binary -btrl Y.o -L. -lX
这时执行措施就会获得如下功效:
./binary
CObjet::STRINGX [001]
STRINGY [001]