用汇编的眼光看C++(之指针)

发表于:2012-5-15 09:35

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:feixiaoxing    来源:51Testing软件测试网采编

  指针是我们在C/C++中经常遇到的一种数据类型。指针用的好,可以提高代码的可读性;但是如果使用不恰当,反而会造成很大的麻烦。指针,也就是指向某一种数据类型的地址。这种类型很多,它可以是编程语言自带的类型,比如说int、long、short、char、float、double、int;也可是是指向某一种自定义数据类型,可以使union、struct或者是class;甚至指向的数据类型本身即是指针,比如说int*、char*、short**;当然指针还可以是指向一片内存,表示具有一定长度的起始地址,比如说int(*pData)[4];最后,指针还可以是函数指针,直接指向函数运行的第一个字节。

  (1)普通数据类型指针

  普通数据类型指针相对概念比较简单,它表示指向的区域就是普通数据类型的空间。我们可以看下面一段示例代码:

43:       int  m = 10;
004012F8   mov         dword ptr [ebp-4],0Ah
44:       char* p = (char*) &m;
004012FF   lea         eax,[ebp-4]
00401302   mov         dword ptr [ebp-8],eax
45:       float* f = (float*) &m;
00401305   lea         ecx,[ebp-4]
00401308   mov         dword ptr [ebp-0Ch],ecx
46:       short* s = (short*) &m;
0040130B   lea         edx,[ebp-4]
0040130E   mov         dword ptr [ebp-10h],edx
47:       *p = 2;
00401311   mov         eax,dword ptr [ebp-8]
00401314   mov         byte ptr [eax],2
48:       *f = 2.4f;
00401317   mov         ecx,dword ptr [ebp-0Ch]
0040131A   mov         dword ptr [ecx],4019999Ah
49:       *s = 10;
00401320   mov         edx,dword ptr [ebp-10h]
00401323   mov         word ptr [edx],offset process+46h (00401326)

  上面的一段代码出现了四种数据类型,三种指针,我们可以一一梳理一下。m、p、f、s都是函数内部的临时变量,因为指针也是一种数据类型,它保存的数据不再是一种char或者是short、int数据,而是一种地址。所以我们对p、f、s进行复制的时候,都是把m的地址一一拷贝给他们的。所以虽然指针类型不同,实际上p、f、s的数值是一样的。下面对指针指向的空间进行数据赋值的时候,就和指针类型相关了。一般来说,如果指针为char类型,那么计算就局限在指针指向的那一个字节里面;如果指针是int类型,那么运算的范围就是指针指向的连续4个字节;当然如果指针是数据结构体或者是class类型,那么指针操作的内存区域就更大了。所以,我们返回到代码的时候发现,*p=2只是操作了一个byte,*f=2.4f的时候,操作的是四个byte、也就是dword,*s=10的时候,赋值的就是一个word,这里0x401326处其实就是数据0x00 0A。函数内的变量进过这一番折腾之后,m数值还是10吗?大家可以好好思考一下?(其实是0x4019000a)

  (2)函数类型指针

  下面是一段有趣的代码,可以查看函数的地址。

void add()
{
 printf("hello!\n");
}


void process(int* q)
{
 int* address = (int*)add;

 __asm{
  call address
 }
}

  这段代码使用了嵌入式汇编,但是理解上面没有什么困难,感兴趣的同学可以直接拷贝到VC上面进行编译,当然还要加上头文件和main函数。通过代码,我们可以发现其实address就是一个地址,call address其实和call add是一样的。

  (3)指针的指针

  指针的指针,其实就是说我们指针指向的数据类型本身就是指针。但是,总之一句,指针是地址,那么指向地址数据的指针本身也是地址。

46:       int* pp = &p;
004012FF   lea         eax,[ebp-4]
00401302   mov         dword ptr [ebp-8],eax
47:       int** ppp = &pp;
00401305   lea         ecx,[ebp-8]
00401308   mov         dword ptr [ebp-0Ch],ecx
48:       int*** pppp = &ppp;
0040130B   lea         edx,[ebp-0Ch]
0040130E   mov         dword ptr [ebp-10h],edx
49:       assert(sizeof(p) == 4);
50:       assert(sizeof(pp) == 4);
51:       assert(sizeof(ppp) == 4);
52:       assert(sizeof(ppp) == 4);

31/3123>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号