为什么 [intro.execution]/12 认为访问 volatile glvalue 是副作用?
Why an access to a volatile glvalue is considered a side effect by [intro.execution]/12?
术语 volatile
在 [intro.execution]/12 中的相关性是什么?
Reading an object designated by a volatile
glvalue ([basic.lval]),
modifying an object, calling a library I/O function, or calling a
function that does any of those operations are all side effects, which
are changes in the state of the execution environment. Evaluation of
an expression (or a sub-expression) in general includes both value
computations (including determining the identity of an object for
glvalue evaluation and fetching a value previously assigned to an
object for prvalue evaluation) and initiation of side effects. When a
call to a library I/O function returns or an access to a volatile
object is evaluated the side effect is considered complete, even
though some external actions implied by the call (such as the I/O
itself) or by the volatile access may not have completed yet.
volatile
的全部目的是向编译器指示 "you don't really know exactly what the result of accessing this variable is, so don't mess about with it"。
例如我们有:
int x = 7;
...
int func1()
{
return x;
}
...
int func2()
{
return func1() + func1();
}
编译器可以(有些人认为应该)将其转换为 return 2 * func1();
[这是通过单个加法简单计算的]。
但是,如果 x
是一个硬件寄存器 [因此 return x;
实际上表现得像 return x++;
],它随着每次读取而改变(例如,它是一个计数器寄存器),那么 func1()+func1()
不能也不应优化为 2 * func1();
- 为避免编译器这样做 volatile int x;
会导致这种情况发生 [不幸的是,没有办法在纯 C++ 代码中导致此行为 /需要一些真正的硬件]
硬件寄存器,这是volatile
的正常use-case(通常与指针结合,但不一定是),寄存器的读取可能具有实际的side-effects 在硬件上——例如在串行端口 [或网卡、硬盘或其他] 上读取 fifo-register 会影响硬件的状态,因为 fifo 现在有 "moved on"一步。跳过、复制、缓存结果或其他一些此类优化肯定会导致一段驱动程序代码和硬件以不同于程序员想要的方式运行——如果 volatile
不是这样的话被认为具有 side-effect.
术语 volatile
在 [intro.execution]/12 中的相关性是什么?
Reading an object designated by a
volatile
glvalue ([basic.lval]), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression (or a sub-expression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects. When a call to a library I/O function returns or an access to avolatile
object is evaluated the side effect is considered complete, even though some external actions implied by the call (such as the I/O itself) or by the volatile access may not have completed yet.
volatile
的全部目的是向编译器指示 "you don't really know exactly what the result of accessing this variable is, so don't mess about with it"。
例如我们有:
int x = 7;
...
int func1()
{
return x;
}
...
int func2()
{
return func1() + func1();
}
编译器可以(有些人认为应该)将其转换为 return 2 * func1();
[这是通过单个加法简单计算的]。
但是,如果 x
是一个硬件寄存器 [因此 return x;
实际上表现得像 return x++;
],它随着每次读取而改变(例如,它是一个计数器寄存器),那么 func1()+func1()
不能也不应优化为 2 * func1();
- 为避免编译器这样做 volatile int x;
会导致这种情况发生 [不幸的是,没有办法在纯 C++ 代码中导致此行为 /需要一些真正的硬件]
硬件寄存器,这是volatile
的正常use-case(通常与指针结合,但不一定是),寄存器的读取可能具有实际的side-effects 在硬件上——例如在串行端口 [或网卡、硬盘或其他] 上读取 fifo-register 会影响硬件的状态,因为 fifo 现在有 "moved on"一步。跳过、复制、缓存结果或其他一些此类优化肯定会导致一段驱动程序代码和硬件以不同于程序员想要的方式运行——如果 volatile
不是这样的话被认为具有 side-effect.