何时抛弃const合法或非法?(gcc,clang和MSVC)

Pra*_*tic 2 c casting const c99 language-lawyer

何时抛弃const非法?

在许多情况下,const它只是用户利益的注释,由编译器强制执行.这个问题要求什么时候抛弃const是严格违法的,C99标准的哪一部分禁止它(如果有的话)?

我怀疑在某些情况下它一定是非法的,因为我发现const全局范围内的函数指针有时被gcc内联.如果这些函数指针可以在程序的后期合法修改,那么这种优化将是无效的.另外我很确定我已经阅读了关于何时丢弃const在StackOverflow上是非法的解释,但我找不到它.(我认为答案是const只有当一个变量最初没有被声明为时才能抛弃const.)

我已经标记了这个C99,因为我希望这是C99标准中指定的内容,但如果答案可以解释C99的gcc,clang和MSVC实现的共同行为,那么这对我来说也足够了.

(显然这是一个非常基本的问题,所以我确实试过并没有找到专门针对C标准的副本.如果其他人可以指出我一个完全重复,我会很乐意结束投票.在任何一种情况下,我认为这个问题标题至少可以帮助SSO解决这类问题.)

AnT*_*AnT 11

抛弃永恒从不违法.你可以随意和合法地做到你想要的.但是,在将const括起来之后尝试修改指向的对象可能会导致未定义的行为(或者可能不会,这取决于具体情况).

C99明确指出

6.7.3类型限定符

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

(C11为6.7.3/6).

请注意,const在C(和C++)中使用两个独立且非常不同的角色:对象本身的 const限定和对象访问路径的 const限定.

const int a = 42;  // `a` is a const-qualifiet object

int b = 5;         // `b` is not const-qualified
const int *p = &b; // `*p` is a const-qualified access path to `b`
Run Code Online (Sandbox Code Playgroud)

在后一种情况下,constness可以合法地抛弃,并且结果非const访问路径可以用于修改对象,前提是对象本身不是const

*(int *) p = 6; // nothing formally wrong with it
Run Code Online (Sandbox Code Playgroud)

这就是我们有能力抛弃语言中的常数的原因.

但是前者(对象本身的常量)不能被覆盖

*(int *) &a = 43; // undefined behavior
Run Code Online (Sandbox Code Playgroud)

原因很简单 - 一个const对象可以物理地位于只读内存中.即使不是这样,编译器仍然可以在假设对象的值永远不会改变的情况下编译代码.

这意味着在声明中

const int *const cp = &b;
Run Code Online (Sandbox Code Playgroud)

这两者const有着截然不同的含义.第一个(最左边)是"软" const,如果条件合适,可以覆盖它.但第二个const是"硬" const,不能被覆盖.

因此,当您说" const仅仅是编译器强制执行的用户利益的注释"时,只有访问路径的const限定才适用.当谈到对象本身的const-qualifications时,通常只是一个纯粹的概念编译器强制的"注释".