全局const POD类型是否需要执行静态初始化器?
静态初始化器疑惑:编译时常量为何出现在.init_array相关符号列表中
我正在尝试减少共享库中的静态初始化器以提升程序启动时间,核心思路是避免将拥有非平凡构造函数的对象设为静态对象。验证优化效果时遇到了一个问题:
测试程序
#include <iostream> static const char foo[] = "1234567890"; static const std::string bar = "abcdefghij"; int main() { std::cout << foo << std::endl; std::cout << bar << std::endl; }
检查结果
编译后用readelf查看符号表并关联.init_array段,发现foo和bar都出现在过滤结果里:
readelf -s .init_array ./a.out -W | egrep "foo|bar" 11: 0000000000403010 11 OBJECT LOCAL DEFAULT 15 _ZL3foo 12: 0000000000405200 32 OBJECT LOCAL DEFAULT 25 _ZL3bar
foo是编译时常量,按道理不需要静态初始化器,为什么会出现在这个结果里?
解答
你看到的是符号表的关联显示结果,而非foo真的存在于.init_array段中。
.init_array段存储的是程序启动时需要执行的初始化函数指针,readelf -s .init_array的作用是列出所有与.init_array段有符号关联的条目——但这并不意味着这些对象本身在.init_array里,只是它们的符号被工具关联展示了。
对于foo来说:
- 它是编译期即可确定内容的字符数组,编译器会直接把它的内容放在只读数据段(通常是
.rodata),完全不需要运行时初始化,自然不会有对应的初始化函数进入.init_array。 - 之所以
readelf结果里能看到它,是因为符号表中记录了该对象的信息,egrep过滤出了包含foo的行,和.init_array段本身没有直接关联。
真正需要静态初始化的是bar:
std::string拥有非平凡构造函数,编译器会生成对应的初始化函数,并将函数指针放入.init_array段,程序启动时会调用这个函数完成bar的构造。
你可以用更精准的命令验证:
# 直接查看.init_array段的十六进制内容 readelf -x .init_array ./a.out
这里只会看到bar对应的初始化函数地址,不会出现foo的相关内容。
内容的提问来源于stack exchange,提问作者Sathwik Matsa
相关产品推荐
相关产品推荐

