C - 通过const声明访问非const

und*_*gor 6 c const extern

是否const通过constC标准允许的声明访问非对象?例如,以下代码保证在符合标准的平台上编译和输出23和42?

翻译单位A:

int a = 23;
void foo(void) { a = 42; }    
Run Code Online (Sandbox Code Playgroud)

翻译单位B:

#include <stdio.h>

extern volatile const int a;
void foo(void);

int main(void) {
    printf("%i\n", a);
    foo();
    printf("%i\n", a);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在ISO/IEC 9899:1999中,我刚刚发现(6.7.3,第5段):

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

但在上面的例子中,对象没有定义为const(但只是声明).

UPDATE

我终于在ISO/IEC 9899:1999中找到了它.

6.2.7,2

引用同一对象或函数的所有声明都应具有兼容类型; 否则,行为未定义.

6.7.3,9

要使两种合格类型兼容,两者都应具有相同类型的兼容类型; [...]

所以,它未定义的行为.

Ste*_*sop 5

TU A包含(唯一)的定义a.所以a真的是一个非const对象,它可以从A中的函数中访问,没有任何问题.

我很确定TU B会调用未定义的行为,因为它的声明a与定义不一致.到目前为止,我发现最好的报价是支持UB为6.7.5/2:

每个声明符声明一个标识符,并断言当与声明符相同形式的操作数出现在表达式中时,它指定一个函数或对象,其范围,存储持续时间和声明指定符所指示的类型.

[编辑:提问者后来在标准中找到了适当的参考,请参阅问题.]

这里,B中的声明断言a有类型volatile const int.实际上对象没有(合格)类型volatile const int,它有(合格)类型int.违反语义的是UB.

在实践中,将会发生的是,TU A将被编译a为非const.TU B将被编译为好像a是a volatile const int,这意味着它根本不会缓存值a.因此,如果链接器没有注意到并且反对不匹配的类型,我希望它能够工作,因为我没有立即看到TU B如何可能发出错误的代码.然而,我缺乏想象力与保证行为不同.

AFAIK,标准中没有任何内容可以说volatile文件范围内的对象不能存储在与其他对象完全不同的存储库中,这些对象提供了不同的读取指令.实现仍然必须能够通过volatile例如指针读取普通对象,因此假设例如"正常"加载指令对"特殊"对象起作用,并且在读取指向易失性的指针时使用它. - 合格的类型.但是,如果(作为优化)执行发射的特殊对象的特殊指令,以及特殊指令并未正常工作的对象,然后繁荣.我认为这是程序员的错,虽然我承认我只是在2分钟前发明了这个实现,所以我不能完全相信它符合.