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
的补充表示。没有魔法。
我有以下代码:
#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
的补充表示。没有魔法。