关于指针,我最初的想法就是,所有类型的指针都是一样的,都是4个字节长度。这句话是对的,但是往往会给我们带来“幻觉”,从而误导我们的判断!就像“幻城”中的幻术师所施展的幻术,真假难辨!
首先,先让我们看看以下情况:
问题:
C/C++ code
int a[]={1,2,3,4,5,6,7,8,9};
short *p=(short*)(a+2);
short *q=(short*)a;
a[p-q]=?
最后,让你判断a[p-q]是多少?当你没经过大脑思考时,你的判断可能是:这还不简单,相差2呗,那就是a[2]呗,就是3呗!当你呗呗呗的时候,你已经范了一个致命的错误,答案是a[4],即5。别忘了p和q都是short*的指针类型!可能你会喋喋不休,说:short*怎么了,指针都是4个字节长,p存储的地址就是a+2后的地址啊,q就是存储的a的地址啊!那你有没有想过相同类型的地址相减的操作返回的是什么?其过程并不是简单的指针所指的地址进行相减,然后返回地址值的差值;指针想相减过程其实是地址相减求出所指向的内存地址所间隔的字节数,然后再与指针多对应类型大小进行相比,即(地址相减得到的字节数)/sizeof(short); 这样,p和q所指向的地址相差的字节数数2×4=8个字节,然后再8/sizeof(short) = 4。所以最后a[p-q] = a[4] = 5。
让我们看看汇编语言是怎么处理的:
int a[]={1,2,3,4,5,6,7,8,9};
0040135E mov dword ptr [a],1
00401365 mov dword ptr [ebp-24h],2
0040136C mov dword ptr [ebp-20h],3
00401373 mov dword ptr [ebp-1Ch],4
0040137A mov dword ptr [ebp-18h],5
00401381 mov dword ptr [ebp-14h],6
00401388 mov dword ptr [ebp-10h],7
0040138F mov dword ptr [ebp-0Ch],8
00401396 mov dword ptr [ebp-8],9
short *p=(short*)(a+2);
0040139D lea eax,[ebp-20h]
004013A0 mov dword ptr [p],eax
short *q=(short*)a;
004013A3 lea eax,[a]
004013A6 mov dword ptr [q],eax
printf("k=%d/n", a[p-q]);
004013A9 mov eax,dword ptr [p]
004013AC sub eax,dword ptr [q] // 相减后寄存器eax中的值是8(……1000)
004013AF sar eax,1 // 将其进行右移操作,eax的值变为4(……0100)
004013B1 mov esi,esp
004013B3 mov ecx,dword ptr a[eax*4]
004013B7 push ecx
004013B8 push offset string "k=%d/n" (404228h)
004013BD call dword ptr [__imp__printf (404124h)]
004013C3 add esp,8
004013C6 cmp esi,esp
004013C8 call _RTC_CheckEsp (401BC0h)
由此可见,编译器编译后的代码也是这么处理的,支持了我们对指针类型的观点!你是否有点慧眼是真的感觉?哈哈,那好,来猜猜下面的结果,如果你没在3秒钟说出答案,那你就自个找个墙,面壁思过吧!O(∩_∩)O哈哈~
C/C++ code
int a[]={1,2,3,4,5,6,7,8,9};
char*p=(char*)(a+2);
char*q=(char*)a;
a[p-q]=?
一秒……
两秒……
三秒……
你有答案了吗?