将易失性分配给非易失性语义和 C 标准

Assign volatile to non-volatile sematics and the C standard

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

此代码忙等待变量变为 1。如果第一遍 vfoo 没有设置为 1,我会卡在里面吗?

此代码在没有警告的情况下编译。 标准对此有何规定?

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

https://godbolt.org/z/nFd9BB

标准对此的说明包括:

5.1.2.3 Program execution

¶2 Accessing a volatile object, modifying an object, modifying a file, 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 in general includes both value computations and initiation of side effects. Value computation for an lvalue expression includes determining the identity of the designated object.

¶4 In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).

¶6 The least requirements on a conforming implementation are:

  • Accesses to volatile objects are evaluated strictly according to the rules of the abstract machine.
  • ...

特别是从 ¶2 中得出的结论应该是,访问易失性对象与调用 printf 没有什么不同——它不能被省略,因为它有副作用。想象一下您的程序 bar = vfoo; 替换为 bar = printf("hello\n");

However, bar is not volatile qualified.

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

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

Is the compiler allowed to optimize the write to this bar?

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

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

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

.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).

当然不是!

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

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

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