我先总结下你的疑惑:
- y1(const) 与 y3 地址相同,修改了 y3 的值,y1 的值却不改变;
- y2(const) 与 y4 地址相同,修改了 y4 的值,y2 的值却改变了。
这个问题说来话长(以下内容仅针对 C++ 来说)。
C++ 对 const 变量的处理分很多种情况,定义位置、方式、数据类型等,都会影响。例如你的情况:
const int y1 = 1; // 编译器会将 y1 放到符号表中,使用 y1 时直接查表取值
const int& y2 = y1; // 编译器会给 y2 分配内存,与普通变量类似,只是多了 const 修饰符
所以,y3 是不可能影响 y1 的值的。
为了详述以上过程,我用汇编代码来解释一下。在 VS2019 下以 [x86|Debug] 成功编译代码,按 F10 进入调试状态,点菜单 Debug -> Windows -> Disassembly(或按 Alt + 8),查看汇编指令。
定义的区别:
const int y1 = 1;
00B11838 mov dword ptr [y1],1
const int& y2 = y1;
00B1183F lea eax,[y1]
00B11842 mov dword ptr [y2],eax
int& y3 = const_cast<int&>(y1);
00B11845 lea eax,[y1]
00B11848 mov dword ptr [y3],eax
int& y4 = const_cast<int&>(y2);
00B1184B mov eax,dword ptr [y2]
00B1184E mov dword ptr [y4],eax
那么问题来了:既然分配了内存,为什么输出 y1 时的值与 y3 不同呢?
因为符号表里面有 y1 啊。还是来看汇编吧(我写了另一段简单的代码):
int i;
i = y1;
003B187B mov dword ptr [i],1
i = y3;
003B1882 mov eax,dword ptr [y3]
003B1885 mov ecx,dword ptr [eax]
003B1887 mov dword ptr [i],ecx
也就是说,使用 y1 的地方,从来都不用 [y1],而是从符号表里面找到 y1 然后直接使用对应的值。
那么直接使用 [y1] 会怎样呢?
我用汇编实现了一下这个奇怪的需求(我删掉了无关代码):
#include <stdio.h>
int main()
{
const int y1 = 1;
int& y3 = const_cast<int&>(y1);
y3 = 2;
int i;
// 对照:普通赋值
i = y1;
printf("i = %d\n", i);
// 对照:汇编赋值实现 i = y1;
__asm {
lea eax, [y1]
mov ecx, dword ptr[eax]
mov dword ptr[i], ecx
}
printf("i = %d\n", i);
return 0;
}
输出内容:
i = 1
i = 2
于是,终于输出了内存里 y1 地址的真实值,而不是符号表里面记录的值。