什么时候可以完全优化易失性变量?

时间:2015-01-07 09:45:59

标签: c language-lawyer volatile

考虑以下代码示例:

int main(void)
{
  volatile int a;
  static volatile int b;

  volatile int c;
  c = 20;
  static volatile int d;
  d = 30;

  volatile int e = 40;
  static volatile int f = 50;

  return 0;
}

如果没有volatile,编译器可以优化掉所有变量,因为它们永远不会被读取。

我认为ab可以被优化掉,因为它们完全未被使用,请参阅unused volatile variable

我认为cd因为被写入而无法删除,并且必须实际发生对volatile变量的写入。 e应相当于c

GCC不会优化远离f,但它也不会发出任何写入指令。在数据部分中设置50。 LLVM(clang)完全删除f

这些陈述是真的吗?

  1. 如果从未访问过易失变量,则可以将其优化掉。
  2. 静态或全局变量的初始化不计为访问。

2 个答案:

答案 0 :(得分:9)

写入volatile变量(甚至是自动变量)计为可观察行为。

C11(N1570)5.1.2.3/6:

  

符合实施的最低要求是:

     

- 严格按照摘要规则评估对易失性对象的访问   机。

     

- 程序终止时,写入文件的所有数据应与结果相同   根据抽象语义执行程序会产生。

     

- 交互设备的输入和输出动态应按照规定进行   7.21.3。这些要求的目的是无缓冲或行缓冲输出   尽快出现,以确保提示消息实际出现在之前   等待输入的程序。

     

这是该计划的可观察行为

问题是:初始化ef)是否计入"访问"?正如Sander de Dycker所指出的,6.7.3说:

  

对具有volatile限定类型的对象的访问构成是实现定义的。

这意味着它可以由编译器决定是否可以优化ef - 但这必须记录在案!

答案 1 :(得分:4)

严格地说,根据C标准,无法优化访问(读取或写入)的任何易失性变量。标准表示对volatile对象的访问可能具有未知的副作用,并且对volatile对象的访问必须遵循C抽象机器的规则(其中所有表达式都按其语义指定进行评估)。

从强大的标准(强调我的):

  

(C11,6.7.3p7)"具有volatile限定类型的对象可能会以未知的方式进行修改   实施或有其他未知的副作用。因此任何表达引用   对这样的对象应严格按照抽象机的规则进行评估,   如5.1.2.3。"

中所述

接下来,即使简单的变量初始化也应被视为访问。请记住,static说明符也会导致对象被初始化(到0)并因此被访问。

现在已知编译器对volatile限定符的行为有所不同,我猜他们中的很多只会优化示例程序的大多数volatile对象,除了那些具有显式赋值(=)的对象。