指针类型的幻觉

关于指针,我最初的想法就是,所有类型的指针都是一样的,都是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]=?

 

一秒……

两秒……

三秒……

你有答案了吗?

 


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值