与C中的位域混淆

时间:2014-09-09 20:42:16

标签: c bit-fields

在下面的代码中:

#include <stdio.h>

struct
{
  int Member1 : 3;
  int Member2 : 1;
}d2;

int main(){

  d2.Member1 = 7;
  printf("%d\n",d2.Member1);

  return 0;

}

结果是-1,为什么?现在d2的二进制值是什么?

4 个答案:

答案 0 :(得分:4)

因为您没有指定d2.Member1是签名还是未签名,所以由编译器决定,显然您正在使用的那个选择使其成为有符号字段,因此范围为-4到3。 7超出范围,所以它溢出。

改为d2.Member1 unsigned int,并在%u来电中使用printf()而不是%d。 (Demo。)

答案 1 :(得分:1)

您将二进制111分配给3位值。由于您将该字段声明为已签名,这意味着3位长&#39; -1&#39;。当您请求一个整数值时,它会用最左边的位进行左边填充以保留符号。 如果您期望输出7,则将您的位字段声明为unsigned Member1: 3。扩展到完整整数将用0替换丢失的MSB而不是最左边的位。

答案 2 :(得分:1)

引用C90标准:

  

位字段的类型应为 int unsigned int 之一的合格或不合格版本> signed int 即可。是否将(可能合格的)“普通” int 位字段的高位位置视为符号位是实现定义的。位字段被解释为由指定位数组成的整数类型。

所以它是-1,因为你没有明确地将它指定为无符号,并且在你正在使用的C实现中,&#34的高位位置;平原&#34; int位字段被视为符号位。你有一个3比特的比特字段,所有的比特都是1,所以&#39; s -1。

答案 3 :(得分:1)

C语言没有定义int位字段是有符号还是无符号。该决定留待实施。出于这个原因,通常不要声明int位字段。根据您的需要,明确使用signed int或显式unsigned int位字段。 (这是C语言的一个区域,其中int 必然意味着signed int。)

在您的情况下,您的3位int位字段恰好已签名。假设2&s补码表示,这种位字段的值范围是[-4, 3]。您试图为其分配7,导致溢出。在赋值时出现有符号整数溢出的情况是实现定义的。你显然最终得到了-1