最简单的选择可能是将其声明为全局变量,
不要使用const
,这样编译器就不能假设它仍然具有静态初始化程序的值。
int K = 123456;
即使在你的程序中调用任何库函数,链接时优化也无法知道该库函数是否访问此全局变量。如果你使用了
static int K = 123456;
,编译器可以注意到编译单元中没有函数写入该值,也没有传递或返回其地址,因此整个编译单元的逃逸分析可以发现它实际上是一个常量,并可被优化掉。(如果你真的想让它成为
static int K;
,就包含一个全局函数,如
void setK(int x){K=x;}
,你从未真正调用它。没有链接时优化,编译器将不得不假定这个编译单元外的某些东西可能已经调用了这个函数并改变了
K
,而且任何调用不可见函数定义的函数都可能导致这样的调用。)
请注意,volatile const int K = 123456;
对于使其非const
的优化影响要大得多,特别是如果你有使用K
多次的表达式。(但是这两种情况都可能会受到很大的影响,具体取决于可能的优化。常数传播可以是一个巨大的胜利。)编译器需要发出精确加载asm,每次C抽象机读取它时都会加载
K
一次。(例如,读取
K
被认为是可见的副作用,就像从MMIO端口或具有硬件监视点的位置读取一样。)如果你想让编译器每个循环加载一次,并假定
K
是循环不变的,则使用它的代码应该使用
int local_k = K;
。你可以自行决定要多少次重新读取
K
,即在何处/何时重新执行
local_k = K
。
在x86上,使用保持在L1d缓存中的内存源操作数可能不是太大的性能问题,但它将防止自动向量化。
我需要这样做的原因是让学生轻松地修改可执行文件,他们将被要求“破解”示例程序以改变其行为。这个练习对于没有经验的人来说必须足够简单。
对于
这种用例,是的,
volatile
正是你想要的。所有使用都在现场重新读取内存,使其比遵循寄存器中缓存的值稍微简单一些。而且性能基本上是无关紧要的,你也不需要自动向量化。可能只需轻微优化,以便学生不必在每个C++语句之后浏览所有存储/重新加载的内容。像gcc的
-Og
就很理想。
对于MSVC,也许可以尝试使用-O1
或-O2
选项,看看是否会产生混淆。我认为它没有某些不太激进的优化选项,可能是调试构建(适合单步执行C++源代码,但不适合阅读汇编代码),也可能是完全针对大小或速度进行了优化。
最初的回答:
使用MSVC时,可以尝试使用-O1
或-O2
选项,查看是否会有任何混淆情况。该编译器似乎没有一些不太激进的优化选项,可能只有调试构建(适合单步执行C++源代码,但不适合阅读汇编代码)或完全优化大小或速度。
volatile const
有类似的效果吗? - Richtvolatile
!我会更新我的答案。 - Indiana Kernick