C 中的位域

Bit Fields in C

我有以下代码:

#include <stdio.h>
struct test 
{
   int x: 2;
   int y: 2;
};
int main()
{
   test t;
   t.x = -1;
   printf("%d", t.x);
   return 0;
}

这段代码打印了 -1 我能理解,

如果相同的代码,%d被替换为 %x 格式说明符,如下所示:

#include <stdio.h>
struct test 
{
   int x: 2;
   int y: 2;
};
int main()
{
   test t;
   t.x = -1;
   printf("%x", t.x);
   return 0;
}

输出变为ffffffff

请解释为什么会这样。

您的系统(以及几乎所有系统)以 2 的补码形式存储负数。 -1 在 8 位 2 的补码形式中表示为 FFH

您观察到的是“-1”的符号扩展 2 的补码。

%x 打印给定参数值的十六进制表示。 -1 的二进制补码表示,以十六进制表示,为您提供 ffffffff

FWIW:此结果与此处使用位域变量没有特别关系,因为 printf()variadic function.

当您将位字段传递给 printf 时,一个参数数量可变的函数,该值会转换为 int。即使该值只有两位,其二进制值 11 在二进制补码表示中表示 -1,因此该值在发送到 -1 时被符号扩展为整数 -1 =11=]。这是 0xffffffff 在 32 位系统上的十六进制表示。

如果您只想看到两位打印为十六进制,请将您的位域设置为无符号。这将确保在打印之前不会执行符号扩展:

#include <stdio.h>
struct test 
{
   unsigned int x: 2;
   unsigned int y: 2;
};
int main()
{
   struct test t;
   t.x = -1;
   printf("%x", t.x);
   return 0;
}

这将打印 3 (demo)。

这与位域本身无关。发生这种情况是因为 C 语言中的一个模糊规则,称为 默认参数提升 :

If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions.

(强调我的)这条规则也适用于像 printf 这样的可变参数函数:

The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.

所以你的位域在 printf 甚至开始解释它之前被提升为类型 int。符号被保留,所以您看到的是包含值 -1 的二进制补码 int 的十六进制表示。

附带说明一下,我根本不建议您使用位域,因为它们的行为未明确指定并且完全不可移植。 See this.

%x表示printf将以十六进制格式输出它的值。现在,问题是为什么 -1 的输出看起来像 ffffffff (0xffffffff)。

1 byte表示8 bits,在十六进制中,4 bits最多可以容纳f。所以 1 byte 可以用十六进制保存 ff 的最大值。

所以,

Bytes       Hex            Bin
1 byte      ff             11111111
4 byte      ff ff ff ff    11111111 11111111 11111111 11111111

现在,-1代表Two's complement,表示是1的负数。

toggle:   00000000 00000000 00000000 00000001 (to fit in 4 byte)
toggle:   11111111 11111111 11111111 11111110
+1    :                                    +1
----------------------------------------------
value :   11111111 11111111 11111111 11111111
hex   :   ff       ff       ff       ff

因此,0xffffffff-1 的补充表示。没有魔法。