码迷,mamicode.com
首页 > 其他好文 > 详细

浅谈指针的偏移

时间:2015-06-17 20:06:35      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:c++

记得当初学习指针的时候,总是把指针和地址混为一谈,总以为说到指针就是指某个地址而已,后来加强对各类指针的认识以后,才认识到指针不止是简单的地址。

指针是一种类型,通过类型可以声明一个变量并保存一个内存地址,不同类型的指针对保存的地址会有不同的解释,编译器根据指针的类型(对应的偏移量)解引用出相应的数据。

首先在32位程序设计里,指针大小为4bytes,满足2^32 寻址范围。


到底偏移多少:

曾经探究过一个问题,代码如下:

	int a[4][2] = { 0, 1, 2, 3, 4, 5 ,7,8 };
	printf("a = %p,a + 1 = %p\n", a, a + 1);
	printf("range = %d\n", a + 1 - a);
运行结果:

a = 00E7FC58, a + 1 = 00E7FC60
range = 1

问题来了,为何a + 1 - a 不等于8,等于1呢?

汇编代码:

	printf("range = %d\n", a + 1 - a);
00035DDF  lea         eax,[ebp-20h]  
00035DE2  lea         ecx,[a]  
00035DE5  sub         eax,ecx  
00035DE7  sar         eax,3  
00035DEA  mov         esi,esp  
00035DEC  push        eax  
00035DED  push        3DA54h  
00035DF2  call        dword ptr ds:[41204h]  
即,编译器对减去过后的eax进行处理,eax = 8 ,sar eax,3  后eax右移三位编程最后结果1。


思考:

对于指针的操作,编译器是不是早已内嵌完成一套偏移运算呢?

我们来看以下代码:

	int a[4][2] = { 0, 1, 2, 3, 4, 5 ,7,8 };
	printf("*(*(a + 0) + 0) =  %d\n", *(*(a + 0) + 0));
	printf("*(*(a + 1) + 0) =  %d\n", *(*(a + 1) + 0));
	printf("*(*(a + 1) + 1) =  %d\n", *(*(a + 1) + 1));
输出结果很简单,但是在指针解引用编译器如何处理呢?

	printf("*(*(a + 0) + 0) =  %d\n", *(*(a + 0) + 0));
00DF5DC5  push        eax  
	printf("*(*(a + 1) + 0) =  %d\n", *(*(a + 1) + 0));
00DF5DDB  mov         esi,esp  
00DF5DDD  mov         eax,dword ptr [ebp-20h]  
	printf("*(*(a + 1) + 1) =  %d\n", *(*(a + 1) + 1));
00DF5DF6  mov         esi,esp  
00DF5DF8  mov         eax,dword ptr [ebp-1Ch]  
可见,编译器自动找到了相应的地址并取出了我们需要的元素,内嵌完成了一套寻址的偏移运算。


探究:

以下代码偏移规则是怎样的?

	int a[4][2] = { 0, 1, 2, 3, 4, 5 ,7,8 };
	printf("*(a + 0) + 0 =  %p\n", *(a + 0) + 0);
	printf("*(a + 1) + 0 =  %p\n", *(a + 1) + 0);
	printf("*(a + 1) + 1 =  %p\n", *(a + 1) + 1);
结果:

*(a + 0) + 0 =  0060FE1C
*(a + 1) + 0 =  0060FE24
*(a + 1) + 1 =  0060FE28

 实质上 *(a ) + m是一个 int* 类型,所以每加1偏移也就是 4bytes。


再来看:

	int a[4][2] = { 0, 1, 2, 3, 4, 5 ,7,8 };
	printf("a =  %p\n", a);
	printf("a + 1 =  %p\n", a + 1);
结果:

a =  00C7FEA0
a + 1 =  00C7FEA8

实质上a 是一个 int (*)[2]指针,偏移就是 2 * 4bytes。


再来看:

	int a[4][2] = { 0, 1, 2, 3, 4, 5 ,7,8 };
	printf("&a =  %p\n", &a);
	printf("&a + 1 =  %p\n", &a + 1);
结果:

&a =  00C2F96C
&a + 1 =  00C2F98C

实质上&a是一个 int (*)[4][2]指针,&a + 1也就偏移了32bytes,跨越了一个a[4][2]的长度,


总结:

我在想,用什么样的方式才能很好解释指针偏移这个问题,想到一点就是:你需要判断这个指针到底是一个什么类型,我们通过指针类型就可以轻松算出偏移大小。



浅谈指针的偏移

标签:c++

原文地址:http://blog.csdn.net/u010125463/article/details/46531883

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!