C语言中通过void指针间接修改const变量为何出现地址同值不同?
同一内存地址下,const变量与指针取值为何不同?
你遇到的这个现象,本质是编译器常量折叠优化加上修改const变量属于未定义行为共同导致的,下面具体拆解:
1. 编译器的常量折叠在起作用
当你声明const int const_num = 10;时,因为这个变量是const修饰且初始化值是编译期就能确定的常量,编译器会触发常量折叠优化:把所有直接引用const_num的地方,在编译阶段直接替换成字面量10,完全不会在运行时去对应的内存地址读取值。
所以最后一行printf里的const_num,编译后已经是硬编码的10,根本不会去访问0x16af26db8这个地址的内容——哪怕你用指针把这块内存改成了20,也不影响直接引用const_num的输出。
2. 修改const变量属于未定义行为
C语言标准明确规定:通过指针修改被const限定的对象,属于未定义行为。这意味着编译器对此没有任何固定处理要求,想怎么干都行:
- 有的编译器会直接拒绝编译这类代码;
- 有的会让内存值和const变量值同步变化;
- 就像你的情况,编译器做了常量折叠,导致同一地址出现两种"看似矛盾"的结果。
这种现象完全符合标准,因为未定义行为本身就没有约束,不同环境下表现可能完全不同。
验证常量折叠的影响
如果不想让编译器做常量折叠,可以把const_num的初始化值改成编译期无法确定的,比如用运行时生成的值:
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { srand(time(NULL)); const int const_num = rand(); // 编译期无法确定值,不会触发常量折叠 printf("const_num value: %d, const_num address: %p\n", const_num, &const_num); void* ptr = (void*)&const_num; printf("ptr value: %p, ptr reference value %d\n", ptr, *(int*)ptr); *(int*)ptr = 20; printf("ptr value: %p, ptr reference value %d\n", ptr, *(int*)ptr); printf("const_num value: %d, const_num address: %p\n", const_num, &const_num); return 0; }
这时候编译器没法做常量折叠,直接访问const_num就会读取内存地址的值,输出就会和指针取值一致——但要注意,这种修改行为依然是未定义行为,只是表现出了你预期的结果。
内容的提问来源于stack exchange,提问作者Alexander Tsagkaropoulos
相关产品推荐
相关产品推荐

