4
volatile int vfoo = 0;
void func()
{
    int bar;
    do
    {
        bar = vfoo;  // L.7
    }while(bar!=1);
    return;
}

This code busy-waits for the variable to turn to 1. If on first pass vfoo is not set to 1, will I get stuck inside.

This code compiles without warning. What does the standard say about this?

  • vfoo is declared as volatile. Therefore, read to this variable should not be optimized.
  • However, bar is not volatile qualified. Is the compiler allowed to optimize the write to this bar? .i.e. the compiler would do a read access to vfoo, and is allowed to discard this value and not assign it to bar (at L.7).
  • If this is a special case where the standard has something to say, can you please include the clause and interpret the standard's lawyer talk?
4

3 回答 3

5

标准对此的规定包括:

5.1.2.3 程序执行

¶2 访问 volatile 对象、修改对象、修改文件或调用执行任何这些操作的函数都是副作用,即执行环境状态的变化。表达式的评估通常包括值计算和副作用的启动。左值表达式的值计算包括确定指定对象的身份。

¶4 在抽象机器中,所有表达式都按照语义的规定进行评估。如果一个实际的实现可以推断出它的值没有被使用并且没有产生所需的副作用(包括调用函数或访问易失性对象引起的任何副作用),则它不需要评估表达式的一部分。

¶6 对一致性实现的最低要求是:

  • 对 volatile 对象的访问严格按照抽象机的规则进行评估。
  • ...

¶2 的要点尤其应该是访问 volatile 对象与调用之类的东西没有什么不同printf——它不能被省略,因为它有副作用。想象一下你的程序bar = vfoo;被替换为bar = printf("hello\n");

于 2019-11-11T13:42:36.380 回答
2

必须在任何访问时读取 volatile 变量。在您的代码片段中,无法优化读取的内容。编译器知道这bar可能会受到副作用的影响。因此将正确检查条件。

https://godbolt.org/z/nFd9BB

于 2019-11-11T10:57:30.523 回答
0

但是,bar不是 volatile 合格的。

变量bar用于保存一个值。您关心存储在其中的值,还是关心该变量是否根据 ABI 精确表示?

Volatile 会保证你是后者。你的程序依赖于前者。

编译器是否允许优化对该栏的写入?

当然。为什么您可能关心读取的值是否真的写入分配给堆栈上变量的内存位置?

您所指定的只是将读取的值作为退出条件进行测试:

        bar = ...
    }while(bar!=1);

.ie 编译器将对 vfoo 进行读取访问,并允许丢弃此值而不将其分配给 bar(在 L.7 中)。

当然不是!

编译器需要保留通过 volatile read 获得的值足够的时间,以便能够将其与 1 进行比较。但没有更多时间了,因为您以后再也不会使用bar了。

可能是一个奇怪的 CPU 作为条件寄存器中的 EQ1(“等于 1”)标志,每当加载等于 1 的值时就会设置该标志。然后编译器甚至不会暂时存储读取的值,而只是 EQ1 条件测试。

根据您的假设,编译器可以丢弃所有非易失性变量的变量值,非易失性对象几乎没有可能的用途

于 2019-11-13T04:03:37.290 回答