4

我正在回答一个问题并制作了这个测试程序。

#include <stdio.h>
int main()
{
    volatile const int v = 5;
    int * a = &v;
    *a =4;
    printf("%d\n", v);
    return 0;
}

如果没有 volatile 关键字,代码会优化(使用 -O3 apple clang 4.2 编译)var 的变化,它按预期工作并且 const 变量被正确修改。

我想知道一个更有经验的 C 开发人员是否知道标准的一部分是否表明这是不安全的或 UB。

更新: @EricPostpischil 给了我这个标准报价

根据 C 2011 (N1570) 6.7.3 6,程序不得修改其自己的使用 const 限定类型定义的对象:“如果尝试通过使用左值来修改使用 const 限定类型定义的对象非 const 限定类型,行为未定义。” 外部代理可以修改具有 volatile 限定类型的对象,根据 6.7.3 7:“具有 volatile 限定类型的对象可能会以实现未知的方式进行修改或具有其他未知的副作用

我的程序违反了第一条规则,但我认为第二条规则可能会使程序免于第一条规则。

更新 2:

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

如果您查看此引用,您可以看到必须根据某些规则评估 var,我还没有通读所有部分5.1.2.3,但我相信这可能会对这个问题有所帮助。

4

2 回答 2

3

这是不安全的,因为不能保证在其他编译器中使用相同的行为。因此,您的代码依赖于编译器,甚至可能依赖于编译器开关。这就是为什么这是一个坏主意。

于 2013-08-05T18:11:48.297 回答
0

这一行:

int * a = &v;

是违反约束的。编译器必须生成诊断消息,并且可能会拒绝该程序。如果编译器仍然生成可执行文件,那么该可执行文件具有完全未定义的行为(即 C 标准根本不再涵盖该程序)。

违反的约束是volatile也不const能被隐式转换掉。

为了符合 C 标准,指针的指向类型必须具有与被指向对象相同或更强的限定符,例如:

int const volatile *a = &v;

之后你会发现该行*a = 4;会导致编译错误。


可能的尝试可能是:

int *a = (int *)&v;

此行必须编译,但随后会导致未定义的行为通过*a. 未定义的行为由 C11 6.7.3/6 指定(C99 和 C89 有类似的文本):

如果尝试通过使用具有非 const 限定类型的左值来修改使用 const 限定类型定义的对象,则行为未定义。如果尝试通过使用具有非 volatile 限定类型的左值来引用使用 volatile 限定类型定义的对象,则行为未定义。

于 2016-02-15T21:46:19.983 回答