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


107

为了使页面变脏(打开页面表条目中的脏位),我触摸页面的第一个字节,如下所示:

pageptr[0] = pageptr[0];

但是实际上,gcc将通过消除死存储来忽略该语句。为了防止gcc对其进行优化,我将语句重写如下:

volatile int tmp;
tmp = pageptr[0];
pageptr[0] = tmp;

看起来the俩有效,但有些丑陋。我想知道是否有任何指令或语法具有相同的效果?而且我不想使用-O0标志,因为它也会带来很大的性能损失。


8
@Mark -O0将停止优化,但也会降低程序性能。我只想防止此代码段的优化:P
ZelluX 2010年

我想在过去补充一点,即使使用-O0并不能防止无效代码“优化”,例如,当GCC检测到某些代码无效时,它只是将其删除。AFAIK这甚至是一个阶段-O0……但这只是我的经验
平滑软件

Answers:


91

关闭优化可解决此问题,但这不是必需的。一种更安全的选择是使编译器使用volatile类型限定符来优化存储空间是非法的。

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

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

这样,仍然可以优化周围的代码,并且您的代码可以移植到其他不了解GCC #pragma__attribute__语法的编译器中。


2
我想说这比关闭优化更可取。使用此方法,您仍然可以从其他优化中受益。
本S

3
Dietrich Epp的解决方案在ARM4.1编译器不起作用。甚至ZelluX的解决方案也不起作用。在ZelluX的解决方案中使ARM4.1起作用的另一种方法是,使“ temp ”成为全局volatile变量
Oculus Dexter,

1
对于所说的编译器来说,这是非常糟糕的。
Alexey Frunze

1
@Shocker:GCC仍然可以优化变量,而无需优化实际的内存访问。这些是不同的问题。
Dietrich Epp

2
@jww:这种用法符合该博客文章中的描述。volatile意味着必须按写入顺序进行内存访问,这正是我们想要的。换句话说,我们已经仔细考虑过,这意味着我们认为的含义。
Dietrich Epp

184

您可以使用

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

your code

#pragma GCC pop_options

自GCC 4.4起禁用优化。

如果需要更多详细信息,请参阅GCC文档。


3
但是,值得注意的是,这仅适用于整个功能,不适用于特定的陈述:gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/… “在此之后定义的每个功能就好像attribute((为此功能指定了optimize(“ STRING”)))。
西罗Santilli郝海东冠状病六四事件法轮功

134

除了使用新的编译指示之外,您还可以__attribute__((optimize("O0")))根据需要使用。这样的优点是仅适用于单个函数,而不是应用于同一文件中定义的所有函数。

用法示例:

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

3
如果我没有使用-Olevel选项,而是使用了单独打开的个人选项怎么办?(就我而言,我无法确定哪个是单独的优化选项正在破坏代码)
user2284570
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.