C11 6.7.3类型限定词,第7段,内容如下:
具有volatile限定类型的对象可能会以实现未知的方式进行修改,或者具有其他未知的副作用 . 因此,任何涉及这种对象的表达都应严格按照抽象机的规则进行评估,如5.1.2.3所述 .
在以下示例中,第三行中访问的对象是否受上述规则约束?
int x;
volatile int *p = &x;
*p = 42;
换句话说,左值 *p
具有类型 volatile int
的事实是否意味着正在访问易失性对象,或者 p
指向非易失性对象 x
的事实意味着编译器可以使用此知识进行优化并省略volatile访问?
由于它可能是有意义的,我感兴趣的特定用例不在普通C的范围内;它涉及使用pre-C11结构(可以是内联asm或简称为黑盒子)进行线程同步的原子,用于原子比较和交换,具有以下习语:
do {
tmp = *p;
new = f(tmp);
} while (atomic_cas(p, tmp, new) != success);
这里指针 p
的类型为 volatile int *
,但我担心当实际指向的对象是非易失性时会发生什么,特别是编译器是否可以将对 *p
的单一访问转换为以下形式的两次访问:
do {
new = f(*p);
} while (atomic_cas(p, *p, new) != success);
这显然会使代码不正确 . 因此,目标是确定是否所有这些指向的对象实际上都需要 volatile int
.
2 回答
Update 2017年2月18日
下面的答案引用并讨论了标准中的语言,基本原理中的一些矛盾语言和gnu.cc中的一些评论是矛盾 . 有一个缺陷报告基本上有标准应该说的委员会协议(虽然仍然是公开的),并且意图一直是,并且实施总是反映出,重要的是不是对象的波动性(根据标准)但是(访问的左值)的波动性(根据基本原理) . (感谢Olaf提及此DR . )
C11版本1.10的缺陷报告摘要日期:2016年4月DR 476 volatile semantics for lvalues 04/2016打开
No. Because the object accessed is not volatile.
对象
p
是指向volatile int的类型指针 . 但x
不是volatile限定类型的对象 . p的资格会影响通过它进行的访问,但不影响它指向的对象的类型 . 通过volatile左值访问非限定类型对象没有限制 . 因此,通过p访问x不是对volatile属性类型的对象的访问 .(有关访问限定类型对象的限制,请参见6.7.3类型限定符 . 它只是说您无法通过不合格的左值访问易失性限定对象 . )
另一方面,this post引用了国际标准的基本原理6.7.3 - 编程语言 - C:
但是,我无法在标准中找到语言,即语义基于左值类型 . 从gnu.org:
No, because there are no side effects:
即使
*p
的语义必须是volatile的语义,标准仍然说:同样,代码中没有volatile对象 . 虽然只看到
p
的编译单元无法进行优化 .Also keep in mind
因此,仅仅出现挥发性左值不能告诉你"accesses"是什么 . 除了记录的实现行为之外,您无权谈论“从
tmp = *p
单一访问*p
” .不完全确定,但我认为关键是对象类型与对象定义类型之间的区别 .
从C11(n1570)6.3.2.1 p1(脚注省略,emph.mine):
它是左值,它定义了对象对特定访问的类型 . 相反,
*p
不表示定义为volatile的对象 . 例如,同上 . 6.7.3 p6(emph.mine)读如果意图是允许显示的代码被优化,那么问题中的引用可能会读取具有[定义为] volatile属性的类型的对象可能被修改[...]
"Definition"的标识符*)在6.7第5段中定义 .
同上 . 6.7.3 p7(对具有volatile限定类型的对象的访问权限是实现定义的 . )为实现者提供了一些余地,但对我来说,意图似乎是修改由对象表示的对象的副作用
n
应被视为符合要求的实施可观察到 .*)Afaik标准没有在任何地方定义"an object defined with (some type)"所以我把它读作"an object, designated by an identifier declared with (some type) by a definition" .