多了一个“星号”

引用注明>> 【作者:张佩】【原文:www.YiiYee.cn/blog

国庆假期我看WDK 8.1中的sample项目,遇一极有趣问题,和基本的指针使用有关,特缀文于此。请看下面是WDK8.1 msplot项目中的一段代码(经我简化过),三行而已,作一个减法运算。注释中的例值,其期望结果应是0x10,但意外得到一个溢出后的大值:

/* struct _PLOTGPC                      */
/* {                                    */
/*  //...                               */
/*  LPVOID pData;                       */ 
/* };                                   */

LPBYTE *pByte = pPlotGPC->pData; // pByte:0x0040fa30
pByte -= (ULONG_PTR)pPlotGPC;    // pPlotGPC:0x0040fa20
pPlotGPC->pData = pByte;         // 结果:0xff3d11b0


pData原来指向位于紧跟在结构体后面的一块内存,是一绝对地址;现在要把pData改成相对地址,即相对于结构体头的偏移。只要把当前值减去结构体起始地址即可。但结果很令人诧异,总是得到一个溢出数。下面是一个例子:

pPlotGPC       : 0x0040fa20
pPlotGPC->pData: 0x0040fa30
结果:0x0040fa30 - 0x0040fa20 = 0xff3d11b0

这个结果让我诧异是不是CPU坏了。但看过汇编后,知道了原因。

00FF107D mov ecx,dword ptr [pPlotGPC]
00FF1080 shl ecx,2 // 乘以4,以左移2实现
00FF1083 mov edx,dword ptr [ebp-0Ch]
00FF1086 sub edx,ecx
00FF1088 mov dword ptr [ebp-0Ch],edx

原来在此减法运算中,减数乃先乘以4然后再相减的:

0x0040fa30 - (0x0040fa20×4)

到底咋回事呢?从哪多出来的×4?且看pByte的定义:

LPBYTE *pByte;

其类型为(LPBYTE*),LPBYTE是(BYTE*)的宏定义,故可转换成:

BYTE** pByte;

所以此乃指针变量的减法操作,指针所指向数据的类型为(BYTE*)。学过C语言的都明白,指针的加减运算,乃加减其类型size的倍数。因其类型仍为一个指针(**的缘故),类型长度根据硬件平台要么4,要么8。我编译出的目标对象乃Win32,指针长度为4。这是汇编代码乘以4的原因了。

细想起来,这很像是一个笔误,解决的办法近乎玩笑,只要去掉一个“*”即可:

LPBYTE *pByte; ==> LPBYTE pByte;

一旦去掉一个*号,指针所指向的数据类型变成了BYTE,而BYTE类型长度为1,就无虞了。

5,302 total views, 1 views today

《多了一个“星号”》有5个想法

发表评论

电子邮件地址不会被公开。