C语言const场景下直接访问变量与*(&i)的输出差异原因
现象原理说明
首先明确:你给出的测试代码本身属于C语言标准定义的未定义行为,出现10、20的输出差异是编译器优化的结果,不是C语言本身规定i和*(&i)语义有区别。
代码本身的违规点
- 被
const限定的变量,C语言标准禁止通过无const限定的指针修改它的值。你的代码里const int i = 10;定义了一个const整型对象,后续直接把&i赋值给非const指针int* pt1本身就属于类型限定符不匹配的违规写法,再通过*pt1 = 20修改const对象的内存值,已经触发未定义行为——这种情况下程序输出任何值、甚至直接崩溃都是符合标准的,编译器不需要为这类代码的运行结果做任何一致性保证。
输出10和20的直接原因
这个结果是常见编译器优化逻辑下的典型产物:
- 对于直接访问
i的语句,编译器看到i是const限定、初始值固定为10的局部变量,会默认这个值永远不会被合法修改,因此做常量折叠优化:根本不生成读取i所在内存的指令,直接把立即数10作为参数传给printf,所以第一行输出固定是10,和i所在内存实际存了什么值没有关系。 - 对于
*(&i)的写法,编译器没有做等价替换为i的优化:因为前面出现了取i地址、通过指针修改对应内存的操作,编译器会老老实实生成“取i的内存地址、解引用读取该地址存储值”的指令,这时候读到的就是你通过pt1强行写入内存的20,因此第二行输出20。
你可以自行编译验证:用gcc编译时加
-O0参数关闭所有优化,两个printf大概率都会输出20;如果加-O2开高等级优化,编译器甚至会直接把*pt1 = 20这段无意义的违规代码删掉,两个printf都会输出10。
常见误区提醒
不要相信“const只是语法检查、本质是栈上变量可以随便改”的错误说法,C标准明确规定修改const对象是未定义行为,编译器可以基于“const对象值永远不变”做任意激进优化,依赖这类违规写法的运行结果没有任何可移植性。
内容的提问来源于stack exchange,提问作者Abhinandan Kushwaha
相关产品推荐
相关产品推荐

