多了一个“星号”

引用注明>> 【作者张佩】【原文http://blog.csdn.net/blog_index

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

/* struct _PLOTGPC                      */
/* {                                    */
/*  //...                               */
/*  LPVOID pData; //偏移为0x10           */ 
/* };                                   */

LPBYTE *pByte = pPlotGPC->pData; // pPlotGPC->pData:0x0040fa30
pByte -= (ULONG_PTR)pPlotGPC;    // pPlotGPC:0x0040fa20
pPlotGPC->pData = pByte;         // 结果:0xff3d11b0。期望的结果应该是0x10。

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

pPlotGPC       : 0x0040fa20
pPlotGPC->pData: 0x0040fa30
结果:0x0040fa30 - 0x0040fa20 = 0xff3d11b0 //不应该是0x10吗?

这个结果让我诧异是不是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)= 0xff3d11b0 // 被减数借位相减,得到一个溢出的大值。

到底咋回事呢?从哪多出来的×4?经过分析后发现和指针的加减法息息相关。且看pByte的定义:

LPBYTE *pByte;

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

BYTE** pByte;

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

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

LPBYTE *pByte; ==> LPBYTE pByte; // 指针类型由BYTE*变为BYTE

一旦去掉一个*号,指针所指向的数据类型变成了BYTE,而BYTE类型长度为1,就无虞了。WDK是微软的驱动开发包,里面的示例项目对驱动开发人员有根本性的指导意义。msplot项目是WDK中唯一的完整的打印机驱动(printer driver)示例。这个bug之所以能够长期存在,我想是因为有机会进行打印机驱动开发的程序员太少的缘故,没有能够及时地把这个bug公布出来。

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值