首先对标题感到抱歉,我不想让它太长或令人困惑。如果有人可以帮助我使它更通用,因为这种情况可能适用于任何类型的位掩码操作。
[以下代码在 Windows 中运行(因此是小端)]
如果我有一个 DWORD(无符号长整型)和一个 WORD(无符号短整型),并且我想从双字中提取低位和高位字,为什么我不能这样做?
DWORD t = 0xAAAABBBB;
WORD loWord = t & 0x0000FFFF;
WORD hiWord = t & 0xFFFF0000;
对于 loWord,我得到正确的答案 0xBBBB,对于 hiWord,我只得到 0(请参阅最后的程序完整列表,以获取结果的打印输出)
我查了一下 Windows 宏是如何执行 HIWORD(_dw) 的,它所做的只是向右移动两个字节,然后像这样执行 AND 操作
DWORD t= 0xAAAABBBB;
WORD hiWord = (t >> 16) & 0xFFFF;
但是我不明白的是,如果我们向右移动两个字节,为什么我们现在还需要执行 AND 运算?为什么甚至需要这种转变,为什么我的原始代码不能按预期工作?
为了说明为什么我对 AND 后的转变感到困惑,这就是我想象的转变工作方式:
0x AA AA BB BB >> 16 -> 0x 00 00 AA AA
这样做0x 00 00 AA AA & 0x00 00 FF FF
在我看来毫无意义?我缺少什么?
更准确地说,宏首先将 DWORD 转换为指针,然后进行移位,如下所示(这是确切的宏)
#define HIWORD(_dw) ((WORD)((((DWORD_PTR)(_dw)) >> 16) & 0xffff))
有人可以向我解释一下指针转换的目的吗?我尝试过使用和不使用,结果是一样的。
这是我在测试过程中使用的一个实际的短程序,用于完整说明该问题:
#include <iostream>
#include <Windows.h>
int main()
{
DWORD t = 0xAAAABBBB;
WORD loWord = t & 0x0000FFFF;
WORD hiWordNoShift = t & 0xFFFF0000;
WORD hiWordShift = (t >> 16) & 0xFFFF;
cout << "t: " << std::hex << t << endl;
cout << "hi (no shift): " << std::hex << hiWordNoShift << endl;
cout << "hi (shift): " << std::hex << hiWordShift << endl;
cout << "lo: " << std::hex << loWord << endl;
system("pause");
return 0;
}
结果是:
t: aaaabbbb
hi (no shift): 0
hi (shift): aaaa
lo: bbbb
Press any key to continue . . .
最佳答案
我认为是这样,因为HIWORD()
应该是通用的并且应该采用CPU寄存器的大小。
在 64 位目标上,通用寄存器(如 RAX)是 64 位寄存器,并且 DWORD_PTR 的大小也是 64 位。 在 32 位目标上,通用寄存器(如 EAX)是 32 位寄存器,并且 DWORD_PTR 的大小也是 32 位。
这样编译器就可以生成更优化的代码。
关于c++ - 从 DWORD 中提取 lo 和 hi 字时为什么需要二进制移位?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57835235/