C 何时可以完全优化可变变量?
考虑以下代码示例:C 何时可以完全优化可变变量?,c,language-lawyer,volatile,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,编译器可以优化掉所有变量,因为它们永远不会被读取 我认为a和b可以
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,编译器可以优化掉所有变量,因为它们永远不会被读取
我认为a
和b
可以优化,因为它们完全没有使用,请参阅
我认为不能删除c
和d
,因为它们是写入到的,写入可变变量实际上必须发生e
应等同于c
GCC不会优化f
,但也不会发出任何写入指令。在数据段中设置50。LLVM(叮当声)完全删除f
这些说法是真的吗
写入可变变量(甚至是自动变量)被视为可观察的行为 C11(N1570)5.1.2.3/6: 一致性实施的最低要求是: -对易失性对象的访问严格按照抽象规则进行评估 机器 -程序终止时,写入文件的所有数据应与 根据抽象语义执行程序会产生错误 -交互设备的输入和输出动态应按照 7.21.3. 这些要求的目的是实现无缓冲或线路缓冲输出 尽快显示,以确保提示消息在 等待输入的程序 这是程序的可观察行为 问题是:初始化(
e
,f
)是否算作“访问”?正如桑德·德戴克(Sander de Dycker)所指出的,第6.7.3节指出:
对具有volatile限定类型的对象的访问由实现定义
这意味着
e
和f
是否可以进行优化取决于编译器,但这必须记录在案 严格来说,根据C标准,无法优化访问(读取或写入)的任何易失性变量。该标准规定,对volatile对象的访问可能会产生未知的副作用,并且对volatile对象的访问必须遵循C抽象机的规则(在C抽象机中,所有表达式都按照其语义进行计算)
来自强大的标准(我的重点):
(C11,6.7.3p7)“具有易失性限定类型的对象可能会以用户未知的方式进行修改
执行或有其他未知的副作用。因此任何引用
对于此类对象,应严格按照抽象机器的规则进行评估,
如5.1.2.3所述。”
接下来,即使是简单的变量初始化也应被视为访问。请记住,静态
说明符也会导致对象被初始化(到0
),从而被访问
现在,已知编译器在volatile限定符上的行为有所不同,我猜很多编译器只会优化掉示例程序中的大多数volatile对象,只有那些具有显式赋值(
=
)的对象除外.可能重复的我认为这个问题更具体地说是关于如何优化可变变量代码>意味着读取d=30代码>?是的,谢谢,马特。我将对其进行编辑。注意声明不是表达式,但它更进一步地说:“构成对具有volatile限定类型的对象的访问的是实现定义的。”这解释了gcc和llvm之间所提到的行为差异。如果volatile自动变量没有其地址,这意味着编译器可以在同样的情况下优化所有访问非易失性变量的指令,但不能将访问后产生的副作用移到它之前的某个点,反之亦然。6.7.3说“构成对具有volatile限定类型的对象的访问的是实现定义的。”,这涉及到您的最后一段。