我的C++程序中具有以下全局常量:
const int K = 123456 ;
当我编译程序时,生成的可执行文件在所有使用该值的地方(数十次)都包含文字值
123456
。但是,如果删除了
const
限定符,则值123456
在整个可执行文件中(在.data
部分中)仅出现一次。这是我要寻找的结果。我希望值
123456
仅出现一次,以便可以通过使用十六进制编辑器编辑.exe文件来简单地对其进行更改。但是,我不想删除
const
限定符,因为我希望编译器防止我不小心修改源代码中的常量。是否可以指示编译器不内联所述常量的值?
我需要这样做的原因是使可执行文件易于被学生“修改”示例程序以更改其行为的学生修改。对于没有经验的人,练习必须足够简单。
最佳答案
最简单的选项可能是将其声明为全局变量,而没有const
,因此编译器无法假定它仍然具有静态初始化程序的值。
int K = 123456;
假设您在程序中调用了任何函数,即使是链接时优化也无法知道库函数不会访问此全局函数。
如果您使用了
static int K = 123456;
,则编译器可能会注意到编译单元中没有函数写入该值,并且这些函数均未传递或返回其地址,因此对整个编译单元进行的转义分析可能会发现它实际上是一个常量,可以对其进行优化。离开。(如果您真的希望它是
static int K;
,请包含一个从未真正调用过的全局函数,例如void setK(int x){K=x;}
。如果没有Link-Time Optimization,编译器将不得不假设该编译单元之外的某些功能可以调用此函数并更改K
,以及任何对其定义不可见的函数的调用都可能导致这样的调用。)请注意,与使非
volatile const int K = 123456;
成为相比,const
可能对优化造成更大的损害,尤其是当您的表达式多次使用K
时。(但是,根据可能的优化方式,这两种方法都可能会造成很大的伤害。恒定传播可能是一个巨大的胜利。)
每次C抽象机读取它时,要求编译器发出一次asm,该asm会精确地加载
K
一次。 (例如,读取K
被认为是可见的副作用,例如从MMIO端口或您具有硬件监视点的位置进行读取。)如果要让编译器每个循环加载一次,并假定
K
是循环不变式,则使用它的代码应该执行int local_k = K;
。由您决定重新读取K
的频率,即您要在什么范围/重做local_k = K
。在x86上,使用在L1d高速缓存中保持高温的内存源操作数可能不是很大的性能问题,但是它将阻止自动向量化。
对于此用例,是的
volatile
正是您想要的。当场从内存中重新读取所有使用的数据,这使其比跟踪缓存在寄存器中的值更加简单。与性能本质上无关紧要,并且您将不需要自动矢量化。可能只是轻度的优化,所以学生不必在每条C++语句后都遍历存储/重新加载所有内容。就像gcc的
-Og
是理想的。使用MSVC,也许尝试
-O1
或-O2
,看看它是否有任何令人困惑的地方。我不认为它有一些选择,但没有太大的优化,它可能是调试版本(对于单步C++源代码来说很不错,不利于阅读asm),或者对大小或速度进行了完全优化。关于c++ - 如何指示VC++编译器不内联常量?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55771389/