引用注明>> 【作者:张佩】【原文: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,232 total views, 3 views today
跟高手学习,常看WDK Sample
跟高手学习,常看WDK Sample。请问什么时候再写WDDM的教程,期待啊!
每次看你的调试,都收获很多。从买你的书,到现在看你的博客。多谢你的分享。
https://code.msdn.microsoft.com/windowshardware/SimRep-File-System-9a4e2206/view/Discussions#17540
俺也发现:WDK 8.1中的sample项目的一个笔误,请看:
https://code.msdn.microsoft.com/windowshardware/SimRep-File-System-9a4e2206/view/Discussions#17540