首页
社区
课程
招聘
[原创]C语指针内幕
2010-1-22 01:01 6922

[原创]C语指针内幕

2010-1-22 01:01
6922
作者:乱雪
来源:hi.baidu.com/lu4nx

R.E.C--F22叫我来篇稿,我实在不知道写啥,也很久没写过技术方面的东西了,刚看书时突然想到了写指针,所有的C语书上都把指针描述得很抽象,所以,老规矩,结合调试器+汇编来理解它。

其实指针和汇编中的间接寻址很像,抽象点说,运用指针可以间接性地访问某变量内容。我说得太抽象了,扔代码上来吧:

/*

C语指针演示,by:乱雪

2010.1.21

*/

#include <stdio.h>

int main(void)
{
int count = 10,lx, *pointer;  //定义两个整型变量count和lx,一个指针pointer。

pointer = &count;   //把count的内存地址赋给pointer,“&”是C语中的地址运算符,用于取内存地址
lx = *pointer;        //用“*”获得指针指向的内容,即 lx = 10
return 0;
}


这时lx的值就是10,可以加句printf("%d \n",lx);看到。

好了,进调试器来解释吧。编译环境VC6.0,调试器是VC6.0默认的调试器。需要观众有汇编语言的基础。

先在int count = 10,lx;处下个断点(右键——“Insert/Remove Breakpoint”),然后按F5,进入调试状态后,会自动在断点处停下来,此时点在断点行处右键——“Go To Disassembly”,来到汇编窗口。

这个时候断点处的代码如下:

mov         dword ptr [ebp-4],0Ah

0A是10的16进制,ebp-4是第一个变量count的地址,mov是传送指令。此句的意思是把10赋值给ebp-4,即count = 10。为了证明这一点,按一下F10单步运行,然后打开Watch窗口,在“名称”里键入&count,就看到了count的地址,如图:

在这里顺便说下,我们定义了三个变量,分别是count、lx和pointer,那么分别对应的地址是ebp-4、ebp-8、ebp-0Ch,因为整型变量占4字节内存,每次ebp都会减少4。

根据刚才代码中的顺序,下一句是pointer = &count;,将pointer指向count的内存地址,我们看对应的汇编代码:

lea         eax,[ebp-4]
mov         dword ptr [ebp-0Ch],eax


前面说过,ebp-4是count变量的内存地址,为了直观点,我把上面的汇编代码改一下:

lea         eax,[count]
mov         dword ptr [pointer],eax


lea指令就是把一个内存变量有效的地址传送给指定的寄存器。第一句lea   eax,[ebp-4]是把count的地址传到eax寄存器,根据刚才在Watch窗口中看到的count地址是0012ff7c,那么eax里面的值就是0012ff7c。第二句mov   dword ptr [ebp-0Ch],eax是把eax中的值传到ebp-0Ch(pointer)中。很明显,pointer = &count;这句代码就等同于pointer = 0012ff7c;。为了直观点,打开Registers窗口,观察寄存器。按三下F10执行三次单步运行,执行完mov dword ptr [ebp-0Ch],eax指令,这个时候寄存器内容如图:

看EAX的值正好是count变量的内存地址0012FF7C。然后在Watch窗口中输入pointer,可以看到pointer的内容是0x0012ff7c,如图:

说明pointer已经指到了count的内存地址了。

接下来看下一句代码lx = *pointer;,对应的汇编代码如下:

mov         ecx,dword ptr [ebp-0Ch]
mov         edx,dword ptr [ecx]
mov         dword ptr [ebp-8],edx


为了直观,我改一下代码:

mov         ecx,dword ptr [pointer]
mov         edx,dword ptr [ecx]
mov         dword ptr [lx],edx

这行代码意思是取出pointer指向的内容赋给变量lx。汇编代码中第一句mov   ecx,dword ptr [ebp-0Ch]意思是把ebp-0Ch(pointer)中的值传入到ecx寄存器中,刚才已经知道,pointer的内容是0x0012ff7c,那么这个时候ecx的值就是0x0012ff7c。第二句mov edx,dword ptr [ecx]意思是取出ecx寄存器中的地址对应的值放入edx寄存器,此时edx寄存器的值就是count的值10了。最后再mov dword ptr [ebp-8],edx,把edx寄存器中的值传到变量lx中。为了观察到整个过程,我们单步运行,直到运行完mov edx,dword ptr [ecx]这句指令,然后观察Registers窗口,看到ECX的值是0012FF7C。ECX的值已经是count的内存地址了:

再单步运行一次,运行完指令mov edx,dword ptr [ecx],再看Registers窗口,EDX的值是0000000A,A是10的十六进制表示。

简单总结下就是:首先将变量的地址放入寄存器中,然后再取出寄存器中存放地址对应的值。C指针的内幕就这样,自己跟着调试一次代码,就会理解了。如有不足之处欢迎一起讨论:)

阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

上传的附件:
  • 1.jpg (19.75kb,301次下载)
  • 2.jpg (29.42kb,296次下载)
  • 3.jpg (22.90kb,296次下载)
  • 4.jpg (29.49kb,293次下载)
  • 5.jpg (29.56kb,297次下载)
收藏
点赞7
打赏
分享
最新回复 (9)
雪    币: 18
活跃值: (80)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ayunaa 2010-1-22 04:46
2
0
这是基础啊
新人的救星啊
雪    币: 109
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
onepc 2010-1-22 08:29
3
0
希望lz有空写点驱动方面的教程。
雪    币: 1489
活跃值: (955)
能力值: (RANK:860 )
在线值:
发帖
回帖
粉丝
仙果 19 2010-1-22 09:12
4
0
基础。呵呵
  谢谢共享
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jerrynpc 2010-1-22 09:31
5
0
哎呀,这不是乱雪大黑客么。膜拜乱雪大黑客

o(∩_∩)o...哈哈
雪    币: 267
活跃值: (24)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
youstar 2 2010-1-22 09:38
6
0
格式排版得不错!
雪    币: 431
活跃值: (1875)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
riusksk 41 2010-1-22 21:36
7
0
注册这么久,终于看见乱雪同志出来放炮了,呵呵
雪    币: 220
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
radarhp 2010-1-23 05:27
8
0
mark下来,慢慢学习。。。
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hknovo 2010-1-23 12:30
9
0
登陆上来回个贴
乱雪写的文章易懂   以前很不明白指针概念。今天看了这篇贴子突然明白了
希望知雪大哥以后 多多写些东西 让我们学习学习
雪    币: 180
活跃值: (76)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
luanx 2010-1-23 14:23
10
0
呵呵 其实没什么 很多东西我都是靠调试才明白的 我是一个不喜欢太理论的人 所以每次看到书上太抽象的描述 都会去试着调试调试
游客
登录 | 注册 方可回帖
返回