C11 6.7.3类型限定符第7段规定:
具有volatile限定类型的对象可能会以实现未知或具有其他未知副作用的方式进行修改。因此,任何引用此类对象的表达式都应严格按照5.1.2.3中描述的抽象机器规则进行评估。
在下面的示例中,第三行访问的对象是否受上述规则的约束?
int x;
volatile int *p = &x;
*p = 42;
换句话说,lvalue *p
的类型为volatile int
是否意味着正在访问一个volatile对象,还是p
指向的非volatile对象x
意味着编译器可以利用这个信息进行优化并省略volatile访问?
由于它可能很有趣,我感兴趣的特定用例超出了普通C的范围;它涉及使用pre-C11构造进行原子线程同步(可能是内联汇编或仅被视为黑匣子)进行原子比较和交换,采用以下惯用法:
do {
tmp = *p;
new = f(tmp);
} while (atomic_cas(p, tmp, new) != success);
这里指针p
的类型将为volatile int *
,但我担心指向的实际对象不是volatile
时会发生什么,特别是编译器是否会将对*p
的单个访问转换为以下两个访问形式:
do {
new = f(*p);
} while (atomic_cas(p, *p, new) != success);
很明显,这会导致代码不正确。因此,目标是确定所有这样指向的对象是否实际需要是volatile int
。
x
不是可观察的副作用。因此,编译器可以根据 as-if 规则进行优化。 - Igor Tandetnikint x
,但您正在谈论一个已定义为易失性的对象。对于声明extern int x
,标准说:“如果尝试通过使用具有非易失性限定类型的lvalue引用已定义为易失性限定类型的对象,则行为未定义。”标准不支持您的兼职易失性。 - philipxyvolatile
,那么最好使用这些屏障而不是依赖于volatile
。另一方面,为了适应保守处理volatile
的编译器而设计的代码将自然地在其他这样的编译器上工作,而无需明确地适应任何一个编译器。 - supercat