我似乎对volatiles
总体上有一个合理的理解,但是有一个看似模糊的案例,其中我不确定按照标准应该如何工作。我已经阅读了C99的相关部分以及关于SO的十几个或更多相关帖子,但在这种情况下找不到逻辑或者解释这个案例的地方。
假设我们有这段代码:
int a, c;
volatile int b;
a = b = 1;
c = b += 1; /* or equivalently c = ++b; */
a
应该像这样评估:
b = 1;
a = b; // volatile is read
或者像这样:
b = 1;
a = 1; // volatile isn't read
同样,c
应该像这样评估:
int tmp = b;
tmp++;
b = tmp;
c = b; // volatile is read
或者像这样:
int tmp = b;
tmp++;
b = tmp;
c = tmp; // volatile isn't read
在a = b; c = b;
之类的简单案例中,事情很清楚。但是上面那些呢?
基本上,问题是,当对象是易失性时,“赋值后左表达式值的表达式”究竟是什么意思?在C99的6.5.16c3中是什么意思?:
赋值运算符将值存储在由指定的对象中 左操作数。赋值 表达式具有左操作数的值 分配后 ,但不是左值。
它是否意味着额外读取volatile以产生赋值表达式的值?
更新:
所以,这就是困境。
如果没有从volatile对象的额外读取中获取“赋值后的对象的值”,则编译器会假设易失性对象b
:
int
值,它可能不是(比如,位0被硬连线到0,这对于硬件寄存器来说并不罕见,我们是应该使用挥发物)由于所有这些,表达式值,如果不是从易失性对象的额外读取中获得的,则不会产生易失性对象的值,标准声称应该是这种情况。
这两种假设似乎都不符合易变物的性质。
如果,OTOH,“赋值后对象的值”是从所述易失性对象的额外隐含读取中获得的,那么使用易失性左操作数评估赋值表达式的副作用取决于是使用表达式值还是不是或完全是任意的,这将是一种奇怪的,意外的和记录不良的行为。
答案 0 :(得分:2)
C11澄清这是未定义的。
您可以找到C11 here的最终草稿。你引用的第二句话现在引用脚注111:
赋值运算符将值存储在左操作数指定的对象中。赋值表达式具有赋值后的左操作数的值, 111)但不是左值。
脚注111说:
111)允许实现读取对象以确定值,但不需要,即使对象具有volatile限定类型。