今天在看SDK教学文章的时候,发现了一个关于位运算符的问题
首先附上关键代码段:
case WM_LBUTTONDOWN:
{
hitPoint.x = LOWORD(lParam);
hitPoint.y = HIWORD(lParam);
MouseClick = TRUE;
InvalidateRect(hWnd,NULL,TRUE);
}
break;
解释下这个代码段:
处理当鼠标左键被按下的时候,保存存储在lParam中的鼠标所在的x,y的位置。但是它是如何被保存的呢?
这里引用了一个结构体hitPoint,我找到它的定义:
POINT hitPoint;
找到关于lParam的定义:
LPARAM lParam;
然后再找到POINT这个结构体变量的定义:
typedef struct tagPOINT
{
LONG x;
LONG y;
} POINT, *PPOINT;
最后找到两处宏定义:
#define LOWORD(l) ((WORD)(l))
#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
找到LPARAM的类型重定义
typedef LONG_PTR LPARAM;
typedef _W64 long LONG_PTR, *PLONG_PTR;
long LONG_PTR
最后再看看WORD和DWORD的类型重定义:
typedef unsigned short WORD; 无符号16位整数
typedef unsigned long DWORD; 无符号32位整数
额,好不容易终于转到了,那么long就是32位有符号整数了。找到了这些东西,现在再来看看宏是怎么处理位运算的。
hitPoint.x = LOWORD(lParam);
这个时候经过宏
#define LOWORD(l) ((WORD)(l))处理会变成
hitPoint.x = ((WORD)(lParam));
还记得刚才lParam的定义吧,是long类型的,而
WORD是unsigned short类型的,这里做了强制类型转换,
使得hinPoint.x得到了低16位的lParam值
再看看
hitPoint.y = HIWORD(lParam);
经过宏替换后
hitPoint.y = ((WORD)(((DWORD)(lParam) >> 16) & 0xFFFF));
这样,我们举个例子好了
首先假设一下lParam的值如下:
左(高位) 右(低位)
1110000101010111 0001010101110001
强制类型转变DWORD后 1110000101010111 0001010101110001
右移16位后 1111111111111111 1110000101010111
按位与运算 & 000000000000000 1111111111111111
------------------------------------------------------------------------
1111111111111111 1110000101010111
最后强制类型转换得到低位的16位 1110000101010111
其实这个数值就是lParam的高16位的值,大家看是不是这样的?
如此一来,我们就将原来lParam = 1110000101010111 0001010101110001
经过语句后最终变成了我们想要得到的效果:
hitPoint.x = 0001010101110001
hitPoint.y = 1110000101010111
好了,我的疑惑现在终于解开了,两个变量终于得到了鼠标x,y轴的坐标了
^_^