首页 文章

使用volatile关键字修改const变量

提问于
浏览
4

我正在回答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 回答

  • 0

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

  • 3

    这一行:

    int * a = &v;
    

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

    违反的约束条件是 volatileconst 可能不会被隐式转换掉 .

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

    int const volatile *a = &v;
    

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


    可能的尝试可能是:

    int *a = (int *)&v;
    

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

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

相关问题