泽强

导航

深入研究C语言 第四篇

这里更多探究的是指针的机制。

debug对下面程序进行分析,记录每一条C语句运行后,相关内存单元的值。

程序a.c

注意理解指针机制

我们编写如下代码:

clip_image001

编译加载进debug查看:

我们先看其反汇编的代码:

clip_image002clip_image003clip_image004

在这里我们对比着C语句分析:

第一条语句是将1000H(16进制,以下16进制用H说明,未说明的都为十进制数据。且汇编语言数据都为16进制,不加H说明。)。放置在变量P(偏移地址01FAH)处。

第二句中,使用*的地方,即*p处,这里的语句被翻译成两句,即:MOV BX,[01FA]和ADD AL,[bx]。在这里我们知道,在汇编中,[]代表的是地址,也就是说先将01FAH地址处的数据放到BX中然后在将DS:[BX]中的数据加到AL中。

第三句中,在使用&处的语句,即p=&ch;处,我们看到在上条语句中,AL最后放到了01A8H处,也就是01A8H处是ch的存放位置。我们看到,p=&ch;这条语句被翻译成了:WORD PTR [01FA],01A8。也就是说,将ch在内存中的存放位置这个数,放在了DS:[01FA]处。从这里我们能看出。1.指针类型也是存放在内存中,存放的内容是一个地址。2.指针类型是一个2字节的。

第四句中,是用*P处。我们看到,首先,将p的地址中存放的地址(也就是ch所占的内存),放到BX中,然后将DS:[BX]的数据放到al中,inc al。我们可以看到,*指针所对应的操作是取指针指向的内存处的数据。

第五句,这里看到了双指针,我们来看,分析上下文我们得出,这句赋值的语句被翻译成了MOV BX,[01A6] 我们看到,这里是将指针P的地址放在了pa中。

我们查看单步执行的过程,对比我们的分析:

clip_image006

在这里我们看到,第一二句执行的时候,确实是将1000H处的数据放到了AL中,也就是P指向的位置的数据。

clip_image008

在这里我们看到,对*p的处理,是将指针内的数据给BX,并将DS:[BX]处的数据放在AL中。

clip_image010

我们看到,这里是将指针p的地址给了pa。

clip_image012

这里调用的时候,是先将01A6H处的数据传给BX,再将DS:[BX]处的数据放到BX中,也就是说*的作用是将这里的数据当做地址向外拿数据。

clip_image014

在这里我们看到char far*,在放入地址的时候,将DS也放入的进去,这里也可以说明far型的指针变量的大小为四个字节。

而且,指针变量还可以被转换为int型的变量。转换过后,是将指针指向的地址作为int型变量的值。

clip_image016

*(char *)n这里是将n的值作为地址,取这里的char型的值。

clip_image018clip_image020

综合来看,指针是一种特殊的类型,指针内存放(这里是指针内,存放)的是一个地址。他有2字节和4字节两种形式。&是取地址符,*是取指针指向位置的数据。

程序b.c

注意Struct指针的用法,指针“+”运算的意义。

我们编写程序如下:

clip_image021

clip_image022clip_image023

我们在反汇编后看到,首先,pstuàname[1]与((*pstu).name[2])在翻译过后的形式是一样的,都是MOV BYTE PTR [ ], 这样的形式。也就是说他们的功能是一样的。其次,对于Struct指针,记录的是Struct的首地址。最后,当指针做“+”运算的时候,其实加上的不是定值,而是它所指向的类型的长度。对于char型是1,对于int型是2,对于自定义类型,是其自定义的数据的长度之和。

我们查看单步的情况:

clip_image025clip_image027clip_image029clip_image031clip_image033clip_image035

那么,这样做的意义在哪儿?指针自加,所加上的是其指向的数据类型的长度,那么我们就可以方便的在程序中使用指针,也可以在循环中使用指针。并且,这样的方式使得程序寻找内存的方式更加多样,更加灵活。

程序c.c

注意理解“[]”运算的意义及数组名与指针的关系。

clip_image036

从整体来说,在这里我们可以看出,p的地址是01d0H,pf的地址是01ceH和01ccH;str的首地址为01caH,而01caH里边存的数据是字符串的首地址0194H;a的首地址为01a8H。

clip_image037

我们可以分析出的一个for循环的位置,是从0206H到022eH。

将01CAH(01CA中结合上下语句可以看出是放的N)处的数据放在BX中,然后将BX+0194H处的数据放到AL中,即是数组中的值。 01caH处放的是pf+n的数据,*(pf+n)就是将[1ca]给了bx,然后将al给了[bx],完成在0:200中写入字符串。

clip_image038

第二个for是024AH到026AH,这里我们可以看出*(str+n)功能与*str+*n是相同的。

clip_image039

第三个for是从026EH到029BH,这里我们看出,其inc WORD PTR[01AC]这条指令被替换成了两条指令:SHL DX,1 shl bx,1和inc word ptr [01CA]。这是因为所取的数据变成了int型。

clip_image040

第四个for,在实现上与第三个for是类似的。

clip_image041clip_image042

综合来看,数组在底层的实现过程和指针在底层实现的过程是一样的。数组名就相当于指向数组空间首地址的指针。而‘数组[下标]’的方式就相当于‘指针+数据类型长度*下标’的方式。

posted on 2014-11-30 20:50  泽强  阅读(672)  评论(0编辑  收藏  举报