最简单的选择可能是将其声明为全局没有const,因此编译器不能假定它仍然具有静态初始化程序的值。
int K = 123456;
假设您在程序中调用 any
如果你使用static int K = 123456;,编译器会注意到编译单元中没有函数写入值,也没有一个函数传递或返回它的地址,因此对整个编译单元的逃逸分析可以发现它实际上是一个常量并且可以被优化掉。
(如果您真的希望它是 static int K;,请包含一个您从未实际调用过的全局函数,例如 void setK(int x){K=x;}。如果没有链接时间优化,编译器将不得不假设此编译单元之外的某些东西可能已经调用这个函数并更改了K,并且任何对定义不可见的函数的调用都可能导致这样的调用。)
请注意,volatile const int K = 123456; 对优化的影响远大于使其成为非const,尤其是当您有多次使用K 的表达式时。
(但其中任何一个都可能造成很大的伤害,具体取决于可能的优化。不断传播可能是一个巨大的胜利。)
每次 C 抽象机读取它时,编译器都需要发出一次准确加载 K 的 asm。 (例如,读取 K 被认为是一种可见的副作用,例如从 MMIO 端口或您有硬件观察点的位置读取。)
如果您想让编译器在每个循环中加载一次,并假设K 是循环不变量,那么使用它的代码应该执行int local_k = K;。由您决定重读K 的频率,即您在什么范围内/重做local_k = K。
在 x86 上,使用在 L1d 缓存中保持热的内存源操作数可能不会造成太大的性能问题,但它会阻止自动矢量化。
我需要这样做的原因是为了让学生可以轻松地修改可执行文件,这些学生将负责“破解”示例程序以改变其行为。对于没有经验的人来说,练习必须足够简单。
对于 this 用例,是的,volatile 正是您想要的。当场从内存中重新读取所有用途,这比跟踪缓存在寄存器中的值要简单一些。
而且性能本质上是无关紧要的,而且您不会想要自动矢量化。可能只是轻微的优化,因此学生不必在每个 C++ 语句之后都费力地存储/重新加载所有内容。就像 gcc 的 -Og 会很理想。
使用 MSVC,也许可以试试 -O1 或 -O2 看看它是否有什么令人困惑的地方。我认为它没有一些优化选项,但不是太激进,它可能是调试构建(对于单步执行 C++ 源代码很好,不利于阅读 asm),或者针对大小或速度进行了全面优化。