我对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 complement
是11111111 11111111 11111111 11111001
的,如果你2's complement
加上1
,它将11111111 11111111 11111111 11111010
.。现在,因为您在结构中只取了 2 位,因此最后到位将是 10
或2
的答案,并且因为它实际上是一个负数,因此输出将-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
.等等。