奇怪的按位运算符组合的目的是什么?
Whats the purpose served by the strange bitwise operator combo?
我正在查看以下代码并发现了以下代码段。
EFI_STATUS
EFIAPI
PeiCreateHob (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN UINT16 Type,
IN UINT16 Length,
IN OUT VOID **Hob
)
{
EFI_STATUS Status;
EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
EFI_HOB_GENERIC_HEADER *HobEnd;
EFI_PHYSICAL_ADDRESS FreeMemory;
Status = PeiGetHobList (PeiServices, Hob);
if (EFI_ERROR(Status)) {
return Status;
}
HandOffHob = *Hob;
//
// Check Length to avoid data overflow.
//
if (0x10000 - Length <= 0x7) {
return EFI_INVALID_PARAMETER;
}
Length = (UINT16)((Length + 0x7) & (~0x7));
...
我不明白我们通过以下操作实现了什么:
Length = (UINT16)((Length + 0x7) & (~0x7));
我知道长度是 16 位对齐的。但是为什么我们要全零呢?据我所知,我们会在操作中丢失 LSB 3 位。这个操作有什么用?
Length = (UINT16)((Length + 0x7) & (~0x7));
该操作执行两个重要步骤:
- 对
Length
的低三位以上的位进行进位
- 确保低三位为空,从而使结果最接近等于或大于原始
Length
值的 8 的倍数。
第 1 部分:四舍五入
如果 Length
的低三位无论如何都点亮(除 000
之外的任何值),增量 0x7
(111
二进制)将通过进位到低三位以上的位。对于低三位的000
,低三位就简单的变成了111
,没有进位。例如:
5 - 00000101
7 - 00000111
=============
12 - 00001100
^-------note carry
另一个例子:
250 - 11111010
7 - 00000111
===============
257 - 100000001
最后,一个在低三位上已经很清楚的例子(因此是 8 的倍数):
24 - 00011000
7 - 00000111
=============
31 - 00011111
第 2 部分:剔除低位
一旦值向上舍入,低三位被剔除以确保最终结果是 8 的倍数。使用我们之前的示例
5 - 00000101
+ 7 - 00000111
===============
12 - 00001100
& ~7 - 11111000
===============
8 00001000
下一个例子
250 - 11111010
+ 7 - 00000111
================
257 - 100000001
& ~7 - 111111000
================
256 - 100000000
最后一个例子:
24 - 00011000
+ 7 - 00000111
===============
31 - 00011111
& ~7 - 11111000
===============
24 - 00011000
总而言之,这只是将 Length
设置为等于或大于 8
倍数的当前值的最接近值。就是这样。
我正在查看以下代码并发现了以下代码段。
EFI_STATUS
EFIAPI
PeiCreateHob (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN UINT16 Type,
IN UINT16 Length,
IN OUT VOID **Hob
)
{
EFI_STATUS Status;
EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
EFI_HOB_GENERIC_HEADER *HobEnd;
EFI_PHYSICAL_ADDRESS FreeMemory;
Status = PeiGetHobList (PeiServices, Hob);
if (EFI_ERROR(Status)) {
return Status;
}
HandOffHob = *Hob;
//
// Check Length to avoid data overflow.
//
if (0x10000 - Length <= 0x7) {
return EFI_INVALID_PARAMETER;
}
Length = (UINT16)((Length + 0x7) & (~0x7));
...
我不明白我们通过以下操作实现了什么:
Length = (UINT16)((Length + 0x7) & (~0x7));
我知道长度是 16 位对齐的。但是为什么我们要全零呢?据我所知,我们会在操作中丢失 LSB 3 位。这个操作有什么用?
Length = (UINT16)((Length + 0x7) & (~0x7));
该操作执行两个重要步骤:
- 对
Length
的低三位以上的位进行进位
- 确保低三位为空,从而使结果最接近等于或大于原始
Length
值的 8 的倍数。
第 1 部分:四舍五入
如果 Length
的低三位无论如何都点亮(除 000
之外的任何值),增量 0x7
(111
二进制)将通过进位到低三位以上的位。对于低三位的000
,低三位就简单的变成了111
,没有进位。例如:
5 - 00000101
7 - 00000111
=============
12 - 00001100
^-------note carry
另一个例子:
250 - 11111010
7 - 00000111
===============
257 - 100000001
最后,一个在低三位上已经很清楚的例子(因此是 8 的倍数):
24 - 00011000
7 - 00000111
=============
31 - 00011111
第 2 部分:剔除低位
一旦值向上舍入,低三位被剔除以确保最终结果是 8 的倍数。使用我们之前的示例
5 - 00000101
+ 7 - 00000111
===============
12 - 00001100
& ~7 - 11111000
===============
8 00001000
下一个例子
250 - 11111010
+ 7 - 00000111
================
257 - 100000001
& ~7 - 111111000
================
256 - 100000000
最后一个例子:
24 - 00011000
+ 7 - 00000111
===============
31 - 00011111
& ~7 - 11111000
===============
24 - 00011000
总而言之,这只是将 Length
设置为等于或大于 8
倍数的当前值的最接近值。就是这样。