如果你期望位域类型除了可以存储 n 个比特以外还有其他值方面的含义,那么你绝不能使用纯粹的 int 作为位域类型。根据 C11 标准,无论 int 是否带符号,int 在位域中都是实现定义的,如下所示:
6.7.2p5:
5 每个由逗号分隔的多重集合指定相同的类型,但对于位域,由于具体实现方式不同,int 指定符号整数或无符号整数的类型是未定义的。
在您的情况下,int 指定的类型是 signed int,在 GCC 中这是默认值(见此处):
是否将“普通” int 位域视为带符号 int 位域或无符号 int 位域(C90 6.5.2、C90 6.5.2.1、C99 和 C11 6.7.2、C99 和 C11 6.7.2.1)。
默认情况下,它被视为带符号 int,但可以通过 -funsigned-bitfields 选项更改。
因此,任何合理的程序都应明确指定 signed int 或 unsigned int,具体取决于当前使用情况。
然后,有符号数字是使用补码、反码还是原码实现是由实现定义的 - 或许是补码和原码,如果是使用补码或原码,那么1位中可以存储的唯一值是符号位,因此是0;因此带符号的1位二进制字段可能只在使用2's complement时才有意义。
您的系统似乎使用2's complement - 这是例如GCC始终使用的:
有符号整数类型是否使用符号和大小、二进制补码还是一的补码,以及特殊值是陷阱表示还是普通值(C99和C11 6.2.6.2)。
GCC仅支持二进制补码整数类型,所有位模式都是普通值。
因此,bit值1
和0
被解释为有符号的2's complement数字:前者设置了符号位,所以它是负数(-1
),而后者没有设置符号位,所以它是非负数(0
)。
因此,在一个2位的带符号位字段中,2个bit的可能模式及其在2's complement机器上的整数值为:
00
- 有int
值0
01
- 有int
值1
10
- 有int
值-2
11
- 有int
值-1
在n位字段中,最小的有符号数字是-2^(n-1),最大的是2^(n-1)-1。
现在,当对一个有符号整数运算进行操作,其等级低于int
时,它首先被转换为int
,因此值-1
被扩展为全宽int
; 默认参数推广也是如此; 当传递给printf
时,该值被扩展为(全宽)int
。
因此,如果您希望从一位位字段得到合理的值,请使用unsigned bit: 1;
或者,如果这被理解为布尔标志,则使用_Bool bit: 1;