【发布时间】:2016-04-25 13:12:45
【问题描述】:
简介: C++ 中的全局静态对象在main() 启动之前进行初始化。考虑:
#include <stdio.h>
int calc_it() {
return 1;
}
int glob = calc_it();
int main() {
printf("glob = %d\n", glob);
return 0;
}
输出为glob = 1,因为calc_it() 和赋值是在main() 开始之前执行的。代码的顺序与它无关。
现在想象一下,您有多个包含类似代码的源文件,并进一步想象它们以某种方式相互依赖(无论出于何种原因,您都想要某种执行顺序。我们不要讨论这是好还是坏的设计。)
标准没有定义执行顺序,但是在 Visual C++ 中有一些方法可以对它们施加一定的顺序。对于全局静态对象,可以在对象定义前使用#pragma init_seg(SECTIONNAME)来指定某个节名。
但最终这只会导致编译器将(__cdecl *)(void) 指向某些链接器部分中的函数指针(它们都以.CRT$XC 开头)。
在链接器确定内存布局之前,节名称按字典顺序排列。默认部分名称为.CRT$XCU。
然后,C/C++ 初始化代码将.CRT$XCA 和.CRT$XCZ 之间的这些段的内容视为指向函数的指针,并一一调用它们。
我们也可以使用#pragma data_seg(SECTIONNAME) 指令手动执行此操作。所以这个:
#include <stdio.h>
void hi_there() {
printf("hi there!\n");
}
int main() {
printf("bye!\n");
return 0;
}
#pragma data_seg(".CRT$XCM")
typedef void (__cdecl *atexit_func)(void);
atexit_func _init_ptr[] = { hi_there };
将输出:
hi there!
bye!
这有多好? :)
问题描述:
AFAIK,自 Visual C++ 2015 起,如果您将 /GL 选项(整个程序优化)与 /OPT:REF 链接器选项(删除未使用的函数和数据)一起使用,这将不再有效。原因可能是从链接器的角度来看,_init_ptr 从未使用过。在较旧的 Visual Studio 版本中,这仍然有效,因为它们从未删除未使用的 data,只使用使用的 code。
问题:如何仅针对单个符号避免这种情况?
【问题讨论】:
标签: c linker visual-c++-2015