(size + 7) & ~7 是什么意思?

What does (size + 7) & ~7 mean?

我正在阅读 Multiboot2 规范。你可以找到它here。与之前的版本相比,它命名了所有的结构"tags"。它们的定义如下:

3.1.3 General tag structure

Tags constitutes a buffer of structures following each other padded on u_virt size. Every structure has following format:

    +-------------------+
u16 | type              |
u16 | flags             |
u32 | size              |
    +-------------------+

type is divided into 2 parts. Lower contains an identifier of contents of the rest of the tag. size contains the size of tag including header fields. If bit 0 of flags (also known as optional) is set if bootloader may ignore this tag if it lacks relevant support. Tags are terminated by a tag of type 0 and size 8.

然后在示例代码中:

for (tag = (struct multiboot_tag *) (addr + 8);
     tag->type != MULTIBOOT_TAG_TYPE_END;
     tag = (struct multiboot_tag *) ((multiboot_uint8_t *) tag
     + ((tag->size + 7) & ~7)))

最后一部分让我很困惑。在 Multiboot 1 中,代码简单得多,您可以直接 multiboot_some_structure * mss = (multiboot_some_structure *) mbi->some_addr 并直接获取成员,而不会像这样混淆代码。

谁能解释一下 ((tag->size + 7) & ~7) 是什么意思?

& ~7 将最后三位设置为 0

正如 chux 在他的评论中提到的,这会将 tag->size 舍入到最接近的 8 的倍数。

让我们仔细看看它是如何工作的。

假设size是16:

 00010000         // 16 in binary
+00000111         // add 7
 --------
 00010111         // results in 23

表达式~7取值7并反转所有位。所以:

 00010111         // 23 (from pervious step)
&11111000         // bitwise-AND ~7
 --------
 00010000         // results in 16

现在假设 size 是 17:

 00010001         // 17 in binary
+00000111         // add 7
 --------
 00011000         // results in 24

然后:

 00011000         // 24 (from pervious step)
&11111000         // bitwise-AND ~7
 --------
 00011000         // results in 24

所以如果 size 的低 3 位全为零,即 8 的倍数,(size+7)&~7 设置这些位然后清除它们,所以没有实际效果。但是,如果这些位中的任何一位为 1,则对应于 8 的位会递增,然后清除较低的位,即数字会向上舍入到最接近的 8 的倍数。

~ 有点不是。 & 是按位与 假设使用 16 位:

7 is 0000 0000 0000 0111

~7 is 1111 1111 1111 1000

任何带0的and'都是0。任何带1的and'都是它本身。于是

N & 0 = 0

N & 1 = N

因此,当您与 ~7 进行 AND 运算时,您基本上清除了最低的三位,而所有其他位保持不变。

感谢@chux 的回答。根据他的说法,如果需要,它会将 size 向上舍入为 8 的倍数。这与 15bpp 绘图代码中完成的技术非常相似:

//+7/8 will cause this to round up...
uint32_t vbe_bytes_per_pixel = (vbe_bits_per_pixel + 7) / 8;

推理如下:

Things were pretty simple up to now but some confusion is introduced by the 16bpp format. It's actually 15bpp since the default format is actually RGB 5:5:5 with the top bit of each u_int16 being unused. In this format, each of the red, green and blue colour components is represented by a 5 bit number giving 32 different levels of each and 32786 possible different colours in total (true 16bpp would be RGB 5:6:5 where there are 65536 possible colours). No palette is used for 16bpp RGB images - the red, green and blue values in the pixel are used to define the colours directly.