我正在回答question并制作了这个测试程序 .
#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 .
UPDATE: @EricPostpischil给了我这个标准报价
根据C 2011(N1570),程序不能修改自己使用const限定类型定义的对象.6.7.3:“如果尝试通过使用左值来修改使用const限定类型定义的对象对于非const限定类型,行为是未定义的 . “外部代理可以修改具有volatile限定类型的对象,根据6.7.3 7:”具有volatile限定类型的对象可能以未知的方式修改实施或有其他未知的副作用
我的程序打破了第一条规则,但我认为第二条规则可以免除第一条规则 .
UPDATE 2:
具有volatile限定类型的对象可能会以实现未知的方式进行修改,或者具有其他未知的副作用 . 因此,任何涉及这种对象的表达都应严格按照抽象机的规则进行评估,如5.1.2.3所述 . 此外,在每个序列点,最后存储在对象中的值应与抽象机器规定的值一致,除非由前面提到的未知因素修改.13)对具有volatile限定类型的对象的访问是什么构成实现-defined .
如果你看一下这个引用,你可以看到var必须按照一定的规则进行评估,我还没有读完所有的部分 5.1.2.3
但我相信这可能会对这个问题有所了解 .
2 回答
这是不安全的,因为无法保证在其他编译器中使用相同的行为 . 因此,您的代码依赖于编译器,甚至可能依赖于编译器开关 . 这就是为什么这是一个坏主意 .
这一行:
是违反约束 . 编译器必须生成诊断消息,并可能拒绝该程序 . 如果编译器仍然生成可执行文件,那么该可执行文件具有完全未定义的行为(即C标准根本不再涵盖该程序) .
违反的约束条件是
volatile
或const
可能不会被隐式转换掉 .为了符合C标准,指针的指向类型必须具有与指向的对象相同或更强的限定符,例如:
之后你会发现
*a = 4;
行会导致编译错误 .可能的尝试可能是:
此行必须编译,但随后它会导致未定义的行为通过
*a
进行读取或写入 . 未定义的行为由C11 6.7.3 / 6指定(C99和C89具有类似的文本):