#define是一个真常量,而const却是由编译器判断实现的常量,严格来说是一个伪常量;
在实际中,由const定义的常量其实仍然是一个变量,只是编译器在编译过程中进行了检查,发现修改就会报错;
如果利用指针得到const int变量的地址,然后根据地址强制改变这个变量的值会有什么情况呢?编译器会不会报错?
变量值会不会改变?
C++代码如下:
void main()
001 {
const int nVar=5;
002
int *p=(int*)(&nVar);
003
*p=7;
004
int _cgd=nVar;
005
cout<<"_cgd="<<_cgd<<endl;
006 }
很遗憾,结果输出为:5
当程序执行到004的时候我们打开调试里的Variables表:
知道其实nVar的值已经被改动;
继续执行到0005
可以发现虽然nVar的值早已修改为7,但是通过004语句的赋值并没有使得_cgd=7;
这是因为nVar的值是已经确定的;虽然你可以通过内存修改它的值,改变这个变量在内存中的二进制序列;但是
凡是以后代码中有nVar的出现,
一律会被编译器优化为初始值,也就是:5;而并不是将当前的nVar实际值进行赋值;
将上述C++代码反汇编:
12: void main()
13: {
004015C0 55 push ebp
004015C1 8B EC mov ebp,esp
004015C3 83 EC 4C sub esp,4Ch
004015C6 53 push ebx
004015C7 56 push esi
004015C8 57 push edi
004015C9 8D 7D B4 lea edi,[ebp-4Ch]
004015CC B9 13 00 00 00 mov ecx,13h
004015D1 B8 CC CC CC CC mov eax,0CCCCCCCCh
004015D6 F3 AB rep stos dword ptr [edi]//以上为子函数初始化过程;
14: const int nVar=5;
004015D8 C7 45 FC 05 00 00 00 mov dword ptr [ebp-4],5
15: int *p=(int*)(&nVar);
004015DF 8D 45 FC lea eax,[ebp-4]
004015E2 89 45 F8 mov dword ptr [ebp-8],eax//将变量nVar偏移地址赋值给[ebp-8],也就是int *p;
16: *p=7;
004015E5 8B 4D F8 mov ecx,dword ptr [ebp-8]
004015E8 C7 01 07 00 00 00 mov dword ptr [ecx],7//通过偏移地址将nVar的内容修改为:7
17: int _cgd=nVar;
004015EE C7 45 F4 05 00 00 00 mov dword ptr [ebp-0Ch],5//
重点:编译器直接将nVar解释为:5;虽然此时内存中的内容其实为:7
此过程为编译器的优化过程;
18: cout<<"_cgd="<<_cgd<<endl;
004015F5 68 C8 10 40 00 push offset @ILT+195(std::endl) (004010c8)
004015FA 8B 55 F4 mov edx,dword ptr [ebp-0Ch]
004015FD 52 push edx
004015FE 68 1C E0 46 00 push offset string "_cgd=" (0046e01c)
00401603 68 90 BE 47 00 push offset std::cout (0047be90)
00401608 E8 7D FC FF FF call @ILT+645(std::operator<<) (0040128a)
0040160D 83 C4 08 add esp,8
00401610 8B C8 mov ecx,eax
00401612 E8 E8 FA FF FF call @ILT+250(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
00401617 8B C8 mov ecx,eax
00401619 E8 C2 FB FF FF call @ILT+475(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
19: }
0040161E 5F pop edi
0040161F 5E pop esi
00401620 5B pop ebx
00401621 83 C4 4C add esp,4Ch
00401624 3B EC cmp ebp,esp
00401626 E8 75 F3 01 00 call __chkesp (004209a0)
0040162B 8B E5 mov esp,ebp
0040162D 5D pop ebp
0040162E C3 ret