C 中用于有符号整数结构 num { int a:3; int b:2; int c:1; } 的位字段



我对C中的位字段感到困惑。谁能解释一下位域概念,或者谁能给我一些很好的资源来理解结构中位域的基本概念?

我试过这个程序,但我无法理解输出。

在 gcc 32 位编译器中

struct num
{
    int a:3;
    int b:2;
    int c:1;
};
void main()
{
    struct num n={8,-6,5};
    printf("%dn%dn%d",n.a,n.b,n.c);
}

输出: 0,-2,-1

好的,因为你是初学者,让我们试着解释一下。.

第一个是int a : 3这意味着您有兴趣存储 3 位,但主要是您分配值 8。现在二进制值 8 是 1000,但由于您只考虑 3 位,取最后 3 个零 (0( 并且输出为 0

现在第二个是int b : 2这意味着您正在存储 2 位。现在从主要开始,您正在编写-6。现在,每当内存中存储任何负数时,它都会存储为2's complement 。因此,二进制值 6 是00000000 00000000 00000000 00000110的,因为它是负数,因此1's complement11111111 11111111 11111111 11111001的,如果你2's complement加上1,它将11111111 11111111 11111111 11111010.。现在,因为您在结构中只取了 2 位,因此最后到位将是 102的答案,并且因为它实际上是一个负数,因此输出将-2

现在内存的第 31 位已经设置好,因此无论您给出什么新数字,它都将被视为负数。现在 c 是 1 位,主要给你 5 这基本上是 0101 因此它将是最后 1 位,因此答案将是 -1 ...

因此,您的编译器行为正常。

位域是一种"微小"整数类型,您可以直接为其指定确切的位大小。 位域只能在结构中使用。 位域的主要用途是 (a( 节省结构中的空间,您将有大量副本,以及 (b( 尝试确认外部强加的存储布局,例如设备驱动程序控制和状态寄存器或网络数据包。

您提供的代码片段给出了意外的结果,因为数字 8(以 2 为基数的 1000(不能用 3 位表示,-6 不能用 2 位表示,而 5 显然不能用 1 位表示。

首先,在位字段声明中,int并不一定意味着signed int。在位字段上下文中,纯int的符号是实现定义的。这是 C 语言中的一个上下文,当您必须明确地说signed [int]是否要确保存储值的符号时。

其次,显然在您的情况下int位字段恰好是有符号的,这意味着在 2 的补码平台上,您的位字段将具有以下范围

  • A : [-4, 3]
  • b : [-2, 1]
  • C : [-1, 0]

您正在分配不适合这些范围的值,从而导致有符号整数溢出。赋值时有符号整数溢出的结果是实现定义的。在您的实现中,2 的补码表示显然被简单地截断为可用位数(采用最低有效位(。

例如,8 以二进制形式1000,这给我们留下了截断为 3 位后的000-6 在 2 的补码二进制中...1111010,这给我们留下了截断后的10,这反过来又是-2 .等等。

最新更新