为什么这段代码需要使用volatile关键字?

4

我在这里找到了这段代码块:

void work(int n) {
  volatile int i=0; //don't optimize away
  while(i++ < n);
}
void easy() { work(1000); }
void hard() { work(1000*1000*1000); }
int main() { easy(); hard(); }

...但是我不明白为什么需要使用volatile关键字来修饰整数i。(这就是整个程序。)我知道volatile可以强制从主内存中读取i的值,但在这种情况下,由于i的值正在被程序本身更新,为什么编译器会认为其他方式是可以的(并优化掉while循环)?


1
Volatile并不会强制访问主内存,它只会强制编译器包含一个读取变量值的指令。由于没有其他内容在写入该值,缓存将永远不会失效,因此该变量很可能不会有任何主内存访问。 - stark
1
@stark:这可能与“主内存”无关,而是为了防止编译器优化本来无用的循环。问题在于一个好的编译器仍然可能检测到变量没有副作用,因为它不为外部世界所知。 - too honest for this site
1个回答

10

因为没有使用volatile关键字,编译器可以自由地观察到循环什么也没做,并将其优化为无效代码。在work()退出后,i的值就会丢失,因此运行循环没有任何可观察的效果。(即使work()通过返回i来公开该值,例如,编译器仍然可以将循环优化为类似i = n的单个赋值语句。)

使用volatile关键字,编译器需要保留对i的所有访问,因此循环不能被优化掉。


我明白了。我重新编写了代码,将i++放在while循环体中(即试图在while循环中“做些事情”而不改变程序),但编译器(gcc -O)仍然将其优化掉了。我对编译器不是很了解,所以不确定它为什么这样做,但这似乎是一种激进的处理方式。预计到达时间:刚看到您的编辑,现在更有意义了。 - Toni
1
由于变量是“auto”类型且其地址未传递,编译器可能仍然检测到它在特定架构上不能产生副作用,从而优化掉循环。但据我所知,当前的编译器都没有这样做,包括众所周知非常激进地优化代码的gcc。 - too honest for this site

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接