我正在回答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。
更新: @EricPostpischil给了我这个标准报价
根据C 2011(N1570),程序不能修改自己使用const限定类型定义的对象.6.7.3:“如果尝试通过使用修改使用const限定类型定义的对象具有非const限定类型的左值,行为是未定义的。“外部代理可以修改具有volatile限定类型的对象,根据6.7.3 7:”具有volatile限定类型的对象可以通过方式进行修改未知的实施或具有其他未知的副作用
我的程序违反了第一条规则,但我认为第二条规则可以免除第一条规则。
更新2:
具有volatile限定类型的对象可能会以实现未知的方式进行修改,或者具有其他未知的副作用。因此,任何涉及这种对象的表达都应严格按照抽象机的规则进行评估,如5.1.2.3所述。此外,在每个序列点,最后存储在对象中的值应与抽象机器规定的值一致,除非由前面提到的未知因素修改.13)什么构成对具有volatile限定类型的对象的访问是实现-defined。
如果你看一下这个引用,你可以看到var必须按照一定的规则进行评估,我还没有阅读5.1.2.3
的所有部分,但我相信这可能会对这个问题有所了解。 / p>
答案 0 :(得分:3)
这是不安全的,因为无法保证在其他编译器中使用相同的行为。因此,您的代码依赖于编译器,甚至可能依赖于编译器开关。这就是为什么这是个坏主意。
答案 1 :(得分: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限定类型定义的对象,则行为是未定义的。