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

考虑以下代码示例:

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可以被优化掉,因为它们是完全未使用的,请参见未使用的volatile变量 。

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

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

这些陈述是真的吗?

  1. 如果永远不会访问volatile变量,则可以将其优化掉。
  2. 静态或全局变量的初始化不计为访问。

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

C11(N1570)5.1.2.3/6:

符合实施的最低要求是:

– 严格根据抽象机器的规则评估对易失性对象的访问。

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

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

这是该程序的可观察行为

问题是: 初始化ef )是否算作“访问”? 正如Sander de Dycker所指出的那样,6.7.3说:

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

这意味着由编译器决定是否可以优化ef – 但必须记录下来!

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

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

(C11,6.7.3p7)“具有挥发性限定类型的对象可能以实现未知的方式进行修改或具有其他未知的副作用 。因此, 任何涉及此类对象的表达式都应严格按照规则进行评估。抽象机 ,如5.1.2.3所述。“

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

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