【问题标题】:What is zero-width bit field [duplicate]什么是零宽度位域[重复]
【发布时间】:2012-11-27 23:18:41
【问题描述】:

可能重复:
Practical Use of Zero-Length Bitfields

为什么有些结构有零宽度位域,为什么需要它?

struct foo {
  int    a:3;
  int    b:2;
  int     :0; // Force alignment to next boundary.
  int    c:4;
  int    d:3;
};

int main()
{
        int i = 0xFFFF;
        struct foo *f = (struct foo *)&i;
        printf("a=%d\nb=%d\nc=%d\nd=%d\n", f->a, f->b, f->c, f->d);
        return 0;
}

上面程序的输出是

manav@os-team:~/programs/test$ ./a.out
a=-1
b=-1
c=-8
d=0

请解释为什么这些值为负数,以及这些变量在结构内部的内存布局?

【问题讨论】:

  • 这是微软的回答,我建议你看看:msdn.microsoft.com/en-us/library/ewwyfdbe(v=vs.71).aspx,即便如此,对齐总是依赖于编译器。
  • 结构 { int a:3;诠释 b:2;整数:0;诠释 c:4;诠释d:3; };这将给出 000aaabb 0ccccddd 的布局,而不是没有 :0; 0000aaab bccccddd 0 宽度字段表示应在下一个原子实体 (char) 上设置以下位域。声明为位字段的数据的顺序是从低位到高位,或其他方式取决于您的架构。
  • 在我的实验中,d 每次在 linux gcc7.2 中运行时都会得到不同的值。但是,在 windows mingw 5.3 下,输出将保持不变。所以它在很大程度上依赖于编译器。

标签: c struct bit-manipulation signed


【解决方案1】:

数字是负数,因为位域是有符号的,也就是说,如果你有一个signed char 变量,它的大小是 8 位,可以容纳 256 个不同的值。一半的值为正,其余为负和 0。最高有效位表示符号(1 表示负,0 表示正)。关于零长度位域,请参见此处:Practical Use of Zero-Length Bitfields

【讨论】:

  • "数字是负数,因为位域是有符号的" --> 不完全是。 OP 的 int 可以解释为 unsigned 字段。这是 C 的一个角落,intsinged int 可以不同。 Ref
【解决方案2】:

here 所述,零长度位域增加了位域之间的对齐。如果我们连续有多个位域,它们的布局是紧凑的,但是如果我们想将其中一个对齐到字节/字/双字边界,我们需要在这个和前一个之间放置一个长度为零的位域。

来自以上链接的示例:

struct on_off {
                  unsigned light : 1;
                  unsigned toaster : 1;
                  int count;            /* 4 bytes */
                  unsigned ac : 4;     // this and
                  unsigned : 4;        // this and
                  unsigned clock : 1;  // this bitfields are next to each other
                  unsigned : 0;
                  unsigned flag : 1;   // this bitfield is at a 4 bytes boundary.
                 } kitchen ;

【讨论】:

    【解决方案3】:

    来自this first hit on a Google search

    长度为 0 的位域必须是未命名的。无法引用或初始化未命名的位域。一个零宽度的位域可以导致下一个域在下一个容器边界上对齐,其中容器的大小与位域的底层类型相同。

    至于问题的第二部分,您将结构中的 一些 位字段设置为全 1,并且由于这些字段已签名,因此这会导致这些字段的值为负。如果将整个结构设置为 1 并查看有符号和无符号表示中的值,您可以更有效地看到这一点,例如

    int main()
    {
        struct foo f;
        memset(&f, 0xff, sizeof(f));
        printf("a=%d\nb=%d\nc=%d\nd=%d\n", f.a, f.b, f.c, f.d); // print fields as signed
        printf("a=%u\nb=%u\nc=%u\nd=%u\n", f.a, f.b, f.c, f.d); // print fields as unsigned
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      内存布局是“取决于”的,您不能指望来自任何特定编译器的任何特定布局。事实上,通过更改其设置,您可能会看到与任何给定编译器不同的布局。不要试图猜测、直觉或依赖布局。

      负数 - 你所有的元素都是有符号的ints,所以它们是负数,因为你已经将每一位初始化为 1,所以你已经设置了符号位。至于 d - 打败了我。错字?

      【讨论】:

      • 您没有回答问题的主要部分 - 零宽度位域的目的是什么?
      猜你喜欢
      • 2021-12-14
      • 1970-01-01
      • 2013-03-15
      • 1970-01-01
      • 2014-07-20
      • 1970-01-01
      • 1970-01-01
      • 2018-02-05
      相关资源
      最近更新 更多