是否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
要使两种合格类型兼容,两者都应具有相同类型的兼容类型; [...]
所以,它是未定义的行为.
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分钟前发明了这个实现,所以我不能完全相信它符合.