先看一个很非常相当基础的C的代码哈~
void main()
{
const int a=5;
int * b=(int*)&a;
*b=8;
printf("%d",a);
}
大家先想想这个地方的输出到底应该是什么吧!
为了大家看的更清楚一些,我把程序稍稍修改一些,如下:
#include <cstdio>
int main()
{
const int a=5;
int * b=(int*)&a;
printf("%d\n",b);
printf("%d\n",*b);
*b=8;
printf("%d\n",a);
printf("%d\n",*b);
return 0;
}
结果输出: 1245024 5 5 8 说明*b=8确实有替a所在的地址赋值。 我在vs2008下编译输出汇编文件,摘选main函数部分汇编代码,加上我的理解注释,如下: _b$ = -20 ; size = 4 _a$ = -8 ; size = 4 _main PROC ; COMDAT ; 4 : { push ebp mov ebp, esp //esp为堆栈指针,ebp=esp sub esp, 216 ; 000000d8H push ebx push esi push edi lea edi, DWORD PTR [ebp-216] mov ecx, 54 ; 00000036H mov eax, -858993460 ; ccccccccH rep stosd ; 5 : const int a=5; mov DWORD PTR _a$[ebp], 5 //变量a存放在堆栈区,赋值为5 ; 6 : int * b=(int*)&a; lea eax, DWORD PTR _a$[ebp] mov DWORD PTR _b$[ebp], eax //b的值确实是变量a所在的地址 ; 7 : printf("%d\n",b); mov esi, esp mov eax, DWORD PTR _b$[ebp] push eax push OFFSET ??_C@_03PMGGPEJJ@?$CFd?6?$AA@ call DWORD PTR __imp__printf add esp, 8 cmp esi, esp call __RTC_CheckEsp ; 8 : printf("%d\n",*b); mov esi, esp mov eax, DWORD PTR _b$[ebp] mov ecx, DWORD PTR [eax] push ecx push OFFSET ??_C@_03PMGGPEJJ@?$CFd?6?$AA@ call DWORD PTR __imp__printf add esp, 8 cmp esi, esp call __RTC_CheckEsp ; 9 : *b=8; mov eax, DWORD PTR _b$[ebp] mov DWORD PTR [eax], 8 //确实改变了a变量地址的内容 ; 10 : printf("%d\n",a); mov esi, esp push 5 //这里就是问题所在,由于const关键字,编译器认为a与5是等价的,所以不再读取内存,而是直接用5代替a push OFFSET ??_C@_03PMGGPEJJ@?$CFd?6?$AA@ call DWORD PTR __imp__printf add esp, 8 cmp esi, esp call __RTC_CheckEsp ; 11 : printf("%d\n",*b); mov esi, esp mov eax, DWORD PTR _b$[ebp] mov ecx, DWORD PTR [eax] push ecx push OFFSET ??_C@_03PMGGPEJJ@?$CFd?6?$AA@ call DWORD PTR __imp__printf add esp, 8 cmp esi, esp call __RTC_CheckEsp ; 12 : return 0; xor eax, eax ; 13 : } 总结起来,就是const关键字令编译器认为a与常量5等价,所以输出的结果还是5。 可以试试输出下面一句,有惊喜。原因我不解释了,自己想想吧:) printf("%d\n",*(((&a)+1)-1));