小编Elz*_*dir的帖子

能否在序列点之间多次读取易失性变量?

我正在制作自己的 C 编译器,以尝试尽可能多地了解有关 C 的详细信息。我现在正在尝试准确地了解volatile对象是如何工作的。

令人困惑的是,代码中的每个读访问都必须严格执行(C11,6.7.3p7):

具有 volatile 限定类型的对象可能会以实现未知的方式进行修改,或者产生其他未知的副作用。因此,引用此类对象的任何表达式都应严格根据抽象机的规则进行评估,如 5.1.2.3 中所述。此外,在每个序列点,最后存储在对象中的值应与抽象机规定的值一致,除非受到前面提到的未知因素的修改。134)构成对具有易失性限定类型的对象的访问的是实现-定义。

示例:在 中a = volatile_var - volatile_var;,必须读取 volatile 变量两次,因此编译器无法优化a = 0;

同时,序列点之间的评估顺序未确定(C11,6.5p3):

运算符和操作数的分组由语法指示。除非稍后指定,否则子表达式的副作用和值计算是无序的。

示例:b = (c + d) - (e + f)未指定计算添加的顺序,因为它们是无序的。

但是,对未排序对象的评估会产生副作用(例如volatile),行为未定义(C11,6.5p2):

如果标量对象上的副作用相对于同一标量对象上的不同副作用或使用同一标量对象的值的值计算是无序的,则行为是未定义的。如果表达式的子表达式有多个允许的排序,并且在任何排序中出现此类未排序的副作用,则行为未定义。

x = volatile_var - (volatile_var + volatile_var)这是否意味着像未定义这样的表达式?如果发生这种情况,我的编译器应该发出警告吗?

我尝试看看 CLANG 和 GCC 做了什么。既不抛出错误也不发出警告。输出的 asm 显示变量不是按执行顺序读取的,而是从左到右读取的,如下面的 asm risc-v asm 所示:

const int volatile thingy = 0;
int main()
{
    int new_thing = thingy - (thingy + thingy);
    return …
Run Code Online (Sandbox Code Playgroud)

c volatile language-lawyer c11

39
推荐指数
4
解决办法
2578
查看次数

标签 统计

c ×1

c11 ×1

language-lawyer ×1

volatile ×1