如何防止GCC在C语言中优化某些语句?

151
为了使页面变脏(在页面表项中打开脏位),我会这样触碰页面的前几个字节:
pageptr[0] = pageptr[0];

但在实际操作中,GCC会忽略死代码消除的语句。为了防止GCC对其进行优化,我将该语句改写如下:
volatile int tmp;
tmp = pageptr[0];
pageptr[0] = tmp;

看起来这个技巧是有效的,但有点不太美观。我想知道是否有任何指令或语法可以达到相同的效果?而且我不想使用-O0标志,因为它会带来很大的性能损失。


9
@Mark -O0选项会停止优化,但也会降低程序的性能。我只想防止对这段代码片段进行优化 :P - ZelluX
2
我想补充一点,在过去,即使使用-O0也无法防止死代码“优化”,例如,当GCC检测到某些代码没有效果时,它会直接将其删除。据我所知,这是在-O0之前的一个阶段...但这只是我的经验。 - smoothware
3个回答

236

您可以使用

#pragma GCC push_options
#pragma GCC optimize ("O0")

your code

#pragma GCC pop_options

从 GCC 4.4 开始,要禁用优化,请参考 GCC 文档以获取更多详细信息。


1
你能否反向优化单个函数 @CiroSantilliOurBigBook.com? - rollsch
1
@rollsch 我建议尝试使用 pragma GCC optimize ("O3"):https://dev59.com/CVYN5IYBdhLWcg3wlY97 - Ciro Santilli OurBigBook.com
1
@rollsch 我会尝试使用 pragma GCC optimize ("O3"):https://stackoverflow.com/questions/47222127/what-does-pragma-gcc-optimize-o3-mean - undefined

177

除了使用新的编译指示语句外,您还可以使用 __attribute__((optimize("O0"))) 来满足您的需求。这样做的好处是仅适用于单个函数而非同一文件中定义的所有函数。

示例用法:

void __attribute__((optimize("O0"))) foo(unsigned char data) {
    // unmodifiable compiler code
}

3
如果我没有使用-Olevel选项,而是分别使用了各个选项,会发生什么呢?(在我的情况下,我无法确定是哪个单独的优化选项导致了代码出错) - user2284570
1
现在关于volatile的所有建议都已经不再适用了。GCC编译器头文件无法处理volatile + O0。由于-faggressive-loop-optimization是默认的,因此while循环被优化掉了,只有O0可以阻止这种情况发生。因此,为了避免这些问题,现在正确的答案是在未经优化的函数中使用O0并且不使用volatile。 - rickfoosusa

116

关闭优化可以解决问题,但这是不必要的。更安全的方法是使用 volatile 类型修饰符,使编译器无法优化掉存储操作。

// Assuming pageptr is unsigned char * already...
unsigned char *pageptr = ...;
((unsigned char volatile *)pageptr)[0] = pageptr[0];

volatile 类型限定符告诉编译器对内存的存储和加载操作要严格控制。 volatile 的一个用途是让编译器知道内存访问具有副作用,因此必须保留。 在这种情况下,存储具有导致页面错误的副作用,并且您希望编译器保留该页面错误。

这样,周围的代码仍然可以进行优化,而且您的代码还可以在其他不理解GCC的#pragma__attribute__语法的编译器中使用。


3
我认为这比关闭优化更可取。通过这种方法,您仍然可以从其他优化中受益。 - Ben S
3
Dietrich Epp的解决方案在ARM4.1编译器下不起作用。即使是ZelluX的解决方案也没有用。 让这个程序在ARM4.1上运行的另一种方法是,在ZelluX的解决方案中,将“temp”声明为全局易失变量。 - Preetham Nanjappa
3
这对于该编译器来说相当糟糕。 - Alexey Frunze
3
GCC仍然可以优化掉变量,而不必优化掉实际的内存访问。这些是不同的问题。 - Dietrich Epp
4
@jww:这个用法符合那篇博客文章中描述的内容。volatile意味着内存访问必须按照写入的方式进行,这正是我们想要的。换句话说,我们已经仔细考虑过了,它的含义与我们想象中的一样。 - Dietrich Epp
显示剩余15条评论

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