【问题标题】:What does (size + 7) & ~7 mean?(size + 7) & ~7 是什么意思?
【发布时间】:2015-10-23 17:42:35
【问题描述】:

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

3.1.3 通用标签结构

标签构成了一个结构缓冲区,这些结构在u_virt 大小上填充。每个结构都有 以下格式:

 +-------------------+
u16 |类型 |
u16 |旗帜 |
u32 |尺寸 |
    +-------------------+

type 分为两部分。 Lower 包含一个标识符 标签其余部分的内容。 size 包含标签的大小 包括标题字段。如果flags 的位0(也称为 optional) 设置如果引导加载程序可能会忽略此标记,如果它缺少 相关支持。标签以0 类型和大小的标签终止 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) 是什么意思吗?

【问题讨论】:

  • 如果需要,它会返回一个四舍五入的 size 到 8 的倍数。
  • 你必须了解两个概念。首先,它要求您了解按位运算符的工作原理。假设您可以遵循使用 ~ 和 & 的逻辑,那么您需要了解它在做什么以及它为什么起作用。以下答案的组合解释了第一部分的按位逻辑。然后其他答案解释说,整个程序在第二部分以 8 的倍数进行舍入。
  • @jaybers 虽然代码会因注释而受益。 7这个神奇的数字已经准备好避免。代码应该放弃位摆弄、铸造和幻数并使用tag += (tag->size + sizeof *tag -1)/sizeof *tag;,并带有注释。 (现在看到评论消失了。)

标签: c bit-manipulation


【解决方案1】:

正如 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 倍数。

【讨论】:

    【解决方案2】:

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

    7 是 0000 0000 0000 0111

    ~7 是 1111 1111 1111 1000

    任何与 0 相加的都是 0。任何与 1 相加的都是它自己。因此

    N & 0 = 0

    N & 1 = N

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

    【讨论】:

      【解决方案3】:

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

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

      原因如下:

      到目前为止,事情都很简单,但引入了一些混乱 采用 16bpp 格式。它实际上是 15bpp,因为默认格式是 实际上是 RGB 5:5:5,每个 u_int16 的最高位未被使用。在 在这种格式中,红色、绿色和蓝色分量中的每一个都是 由一个 5 位数字表示,每个数字给出 32 个不同的级别,并且 总共 32786 种可能的不同颜色(真正的 16bpp 将是 RGB 5:6:5,其中有 65536 种可能的颜色)。没有调色板用于 16bpp RGB 图像 - 像素中的红色、绿色和蓝色值是 用于直接定义颜色。

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-06
          • 2015-05-17
          • 1970-01-01
          • 1970-01-01
          • 2016-07-13
          • 1970-01-01
          相关资源
          最近更新 更多