【问题标题】:Why an access to a volatile glvalue is considered a side effect by [intro.execution]/12?为什么 [intro.execution]/12 将访问 volatile 泛左值视为副作用?
【发布时间】:2016-01-17 15:33:57
【问题描述】:

[intro.execution]/12 中的 volatile 一词有什么相关性?

[intro.execution]/12:

读取由volatile glvalue ([basic.lval]) 指定的对象, 修改对象、调用库 I/O 函数或调用 执行任何这些操作的函数都是副作用,其中 是执行环境状态的变化。评估 一个表达式(或一个子表达式)通常包含两个值 计算(包括确定对象的身份 glvalue 评估并获取先前分配给 prvalue评估的对象)和副作用的开始。当一个 调用库 I/O 函数返回或访问 volatile 对象被评估,副作用被认为是完整的,甚至 尽管调用隐含的一些外部动作(例如 I/O 本身)或通过 volatile 访问可能尚未完成。

【问题讨论】:

  • volatile 表示读取是无法优化的“可观察行为”。

标签: c++ language-lawyer volatile


【解决方案1】:

volatile 的全部目的是向编译器表明“你并不真正知道访问这个变量的确切结果是什么,所以不要乱来”。

比如说我们有:

 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 的正常用例(通常与指针结合,但并非必须如此),读取寄存器可能会对硬件产生实际的副作用 - 对于例如在串行端口 [或网卡、硬盘或其他] 上读取 fifo 寄存器,将影响硬件的状态,因为 fifo 现在已经“前进”了一步。跳过、复制、缓存结果或其他一些这样的优化肯定会导致一段驱动程序代码和硬件的行为方式与程序员想要的不同——如果volatile不被视为有副作用。

【讨论】:

  • 不!请不要在多线程代码的上下文中提及volatile。它不起作用。硬件寄存器是唯一有效的用例。 (但其余的答案是正确的)。
  • @MartinBonner:我确实指出这是一种糟糕的做事方式。但是,我已将其重写为更加面向硬件。
  • 谢谢。好多了。
猜你喜欢
  • 2014-03-03
  • 1970-01-01
  • 2012-02-28
  • 1970-01-01
  • 1970-01-01
  • 2017-04-15
  • 2023-03-04
  • 1970-01-01
  • 2012-07-02
相关资源
最近更新 更多