关于 Lo、Hi、LoWord、HiWord

时间:2023-03-09 17:11:02
关于 Lo、Hi、LoWord、HiWord

Cardinal 是 4 字节无符号的整型, 先看一个例数:

Cardinal 例数: 4277991664
按字节划分: 第四字节 第三字节 第二字节 第一字节
二进制: 11111110 11111100 11111000 11110000
十六进制: FE FC F8 F0
十进制: 254 252 248 240
按双字节划分: 高两位 低两位
二进制: 1111111011111100 1111100011110000
十六进制: FEFC F8F0
十进制: 65276 63728
本话题会涉及到: Lo、Hi、HiByte、LoWord、HiWord、MakeWord、MakeLong、Int64Rec

譬如有一个 Cardinal 类型的整数:
其十六进制的表示是: $
其二进制表示是:
我们说 Cardinal 是 位的整数, 这里的位是指 "二进制的位数", 不信你数数. 我们需要重点面对的是十六进制, 不管是几进制的数在编译成汇编代码时都是用十六进制表示, 因为它最直观;
我们用十六进制来分析, 也是因为它的直观. 怎么直观的? Cardinal 有 位, 每 位一个字节, 共 个字节;
上面的例数分成字节就是: $、$、$、$, 这明显比二进制简洁、比十进制直观. 其中的 $ 是最低位的字节、$ 是最高位的字节(每字节对应十六进制的两位).
有时我们需要获取其中某个字节或某两个字节, 这虽然用位运算也不难, 但还是有了诸多函数: Lo //获取例数中的 $11
Hi //获取例数中的 $22
LoWord //获取例数中的 $2211
HiWord //获取例数中的 $4433 其中的 Hi 好像有点费解, 为什么获取的不是 $ 而是 $ 呢?
这样理解吧: Hi 获取的是 Lo(获取)的上一个字节. HiByte 和 Hi 基本一样, 如果参数是 位的 Word 类型, 用 HiByte 会更好些(中间会省去一个转换过程). 其中的 HiWord 是个函数, 但 LoWord 并不是个函数, 它是 Word 类型的重命名.
也就是说 LoWord(num) 等价于 Word(num), 这不是类型转换吗?
是的, 所以像 Lo(num) 也可以用 Byte(num) 来代替. 用代码总结一下: var
num: Cardinal;
b1,b2,b3,b4: Byte;
w1,w2: Word;
begin
num := $;
w1 := Word(num);
w2 := HiWord(num);
ShowMessageFmt('w1:%x; w2:%x', [w1,w2]);//w1:2211; w2:4433 b1 := Lo(num);
b2 := Hi(num);
b3 := Byte(w2);
b4 := HiByte(w2);
ShowMessageFmt('b1:%x; b2:%x; b3:%x; b4:%x', [b1,b2,b3,b4]);//b1:11; b2:22; b3:33; b4:44
end; 下一个话题: 我们有时也需要进行上面的反操作, 譬如:
把两个 Byte 合成为一个 Word;
把两个 Word 合成一个 Cardinal;
把两个 Cardinal 合成一个 Int64;
把四个 Byte 合成一个 Cardinal;
把四个 Word 合成一个 Int64 等等 上面说的 Cardinal 也可以是 Integer 或 DWORD. 完成这种工作也有不少函数:
MakeWord、MakeLong、MakeWParam、MakeLParam、MakeLResult、MAKELCID 等等. 仅就 MakeWord、MakeLong 举例: var
num: Cardinal;
b1,b2,b3,b4: Byte;
w1,w2: Word;
begin
b1 := $;
b2 := $;
b3 := $;
b4 := $; w1 := MakeWord(b1, b2);
w2 := MakeWord(b3, b4);
ShowMessageFmt('w1:%x; w2:%x', [w1,w2]);//w1:2211; w2:4433 num := MakeLong(w1, w2);
ShowMessageFmt('num:%x', [num]);//
end; 有没有把两个 Integer 合成为 Int64 的函数呢?
没有, 当然可以写一个; 不过有更方便的处理方式, 那就是 Int64Rec 结构. 举例如下: var
n1,n2: Cardinal;
num64: Int64;
rec: Int64Rec;
begin
n1 := $;
n2 := $AABBCCDD; rec.Lo := n1;
rec.Hi := n2; num64 := Int64(rec);
ShowMessage(IntToHex(num64, )); //AABBCCDD44332211
end; Int64Rec 更多用于反向操作: var
n1,n2: Cardinal;
num64: Int64;
begin
num64 := $AABBCCDD44332211; n1 := Int64Rec(num64).Lo; //或 n1 := Cardinal(num64);
n2 := Int64Rec(num64).Hi; ShowMessageFmt('n1:%x; n2:%x', [n1,n2]);//n1:44332211; n2:AABBCCDD
end;