简介: 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!
那有多好?:)
问题描述:/GL
AFAIK,自 Visual C++ 2015 起,如果您将选项(整个程序优化)与/OPT:REF
链接器选项(删除未使用的函数和数据)一起
使用,这将不再有效。原因可能是从链接器的角度来看,_init_ptr
从未使用过。在较旧的 Visual Studio 版本中,这仍然有效,因为它们从不删除未使用的数据,只删除使用的代码。
问题:如何仅针对单个符号避免这种情况?