什么时候可以完全优化 volatile 变量?
When can a volatile variable be optimized away completely?
考虑这个代码示例:
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
可以优化掉,因为它们完全未被使用,参见 unused volatile variable。
我认为 c
和 d
不能删除,因为它们是写入的,并且写入 volatile 变量必须实际发生。 e
应该等同于 c
。
GCC 不会优化掉 f
,但它也不会发出任何写入它的指令。 50设置在数据部分。 LLVM (clang) 完全删除 f
。
这些说法是真的吗?
- 如果从不访问易失性变量,则可以将其优化掉。
- 静态或全局变量的初始化不算作访问。
写入 volatile 变量(甚至是自动变量)算作可观察的行为。
C11 (N1570) 5.1.2.3/6:
The least requirements on a conforming implementation are:
— Accesses to volatile objects are evaluated strictly according to the rules of the abstract
machine.
— At program termination, all data written into files shall be identical to the result that
execution of the program according to the abstract semantics would have produced.
— The input and output dynamics of interactive devices shall take place as specified in
7.21.3. The intent of these requirements is that unbuffered or line-buffered output
appear as soon as possible, to ensure that prompting messages actually appear prior to
a program waiting for input.
This is the observable behavior of the program.
问题是:初始化(e
、f
)算作"access"吗?正如 Sander de Dycker 所指出的,6.7.3 说:
What constitutes an access to an object that has volatile-qualified type is implementation-defined.
这意味着是否可以优化 e
和 f
取决于编译器 - 但这必须记录在案!
严格来说,根据 C 标准,任何被访问(读取或写入)的 volatile 变量都不能被优化掉。该标准表示访问 volatile 对象可能有未知的副作用,并且访问 volatile 对象必须遵循 C 抽象机的规则(其中所有表达式都按照其语义指定进行评估)。
来自强大的标准(强调我的):
(C11, 6.7.3p7) "An object that has volatile-qualified type may be modified in ways unknown to the
implementation or have other unknown side effects. Therefore any expression referring
to such an object shall be evaluated strictly according to the rules of the abstract machine,
as described in 5.1.2.3."
因此,即使是简单的变量初始化也应该被视为访问。请记住 static
说明符也会导致对象被初始化(到 0
)并因此被访问。
现在已知编译器对 volatile 限定符的行为有所不同,我猜他们中的很多人只会优化示例程序中的大部分 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
可以优化掉,因为它们完全未被使用,参见 unused volatile variable。
我认为 c
和 d
不能删除,因为它们是写入的,并且写入 volatile 变量必须实际发生。 e
应该等同于 c
。
GCC 不会优化掉 f
,但它也不会发出任何写入它的指令。 50设置在数据部分。 LLVM (clang) 完全删除 f
。
这些说法是真的吗?
- 如果从不访问易失性变量,则可以将其优化掉。
- 静态或全局变量的初始化不算作访问。
写入 volatile 变量(甚至是自动变量)算作可观察的行为。
C11 (N1570) 5.1.2.3/6:
The least requirements on a conforming implementation are:
— Accesses to volatile objects are evaluated strictly according to the rules of the abstract machine.
— At program termination, all data written into files shall be identical to the result that execution of the program according to the abstract semantics would have produced.
— The input and output dynamics of interactive devices shall take place as specified in 7.21.3. The intent of these requirements is that unbuffered or line-buffered output appear as soon as possible, to ensure that prompting messages actually appear prior to a program waiting for input.
This is the observable behavior of the program.
问题是:初始化(e
、f
)算作"access"吗?正如 Sander de Dycker 所指出的,6.7.3 说:
What constitutes an access to an object that has volatile-qualified type is implementation-defined.
这意味着是否可以优化 e
和 f
取决于编译器 - 但这必须记录在案!
严格来说,根据 C 标准,任何被访问(读取或写入)的 volatile 变量都不能被优化掉。该标准表示访问 volatile 对象可能有未知的副作用,并且访问 volatile 对象必须遵循 C 抽象机的规则(其中所有表达式都按照其语义指定进行评估)。
来自强大的标准(强调我的):
(C11, 6.7.3p7) "An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3."
因此,即使是简单的变量初始化也应该被视为访问。请记住 static
说明符也会导致对象被初始化(到 0
)并因此被访问。
现在已知编译器对 volatile 限定符的行为有所不同,我猜他们中的很多人只会优化示例程序中的大部分 volatile 对象,除了具有显式赋值的对象 (=
).