找到你要的答案

Q:Bit Fields in C

Q:C中的位字段

I have the following code:

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

This snippet prints -1 which I can understand,

If the same code, %dis replaced with %x format specifier like below:

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

The output becomes ffffffff.

Please explain why this is the case.

我有以下代码:

#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,我能理解,

如果相同的代码,%不同意%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。

请解释这是为什么。

answer1: 回答1:

%x prints the hex representation of the value of the given argument. The two's complement representation of -1, in hex, gives you that ffffffff.

FWIW: This outcome is not particularly related to use of bit-filed variable here, as printf() is a variadic function.

% x打印给定参数值的十六进制表示形式。二的补码表示1,十六进制,给你ffffffff。

总的来说:这一结果是不使用这里的位场变量是相关的,因为printf()是一个可变参数函数。

answer2: 回答2:

When you pass your bit field to printf, a function with variable number of arguments, the value undergoes a conversion to int. Even though the value has only two bits, its binary value of 11 means -1 in two's complement representation, so the value gets sign-extended into an integer -1 when it is sent to printf. This is 0xffffffff in hex representation on 32-bit systems.

If you would like to see only two bits printed as hex, make your bit field unsigned. This will ensure that no sign extension would be performed before printing:

#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;
}

This prints 3 (demo).

当你把你的位场printf,与参数数目可变的功能,价值经历到int的转换,虽然价值只有两位,二进制11表示1的补码表示的价值,因此价值得到符号扩展为整数1时被送到了printf。这是在32位系统0xffffffff进制表示。

如果你想看到只有两位打印为十六进制,使您的位字段无符号。这将确保在打印之前不会执行任何标志扩展:

#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(演示)。

answer3: 回答3:

This has nothing to do with bit fields as such. It happens because of an obscure rule in C called the default argument promotions:

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.

(Emphasis mine) And this rule also applies to variadic functions like 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.

So your bit field is integer promoted to type int before printf even starts interpreting it. The sign is preserved, so what you are seeing is the hex representation of a two's complement int containing the value -1.

As a side note, I would not recommend you to use bit fields at all, as their behavior is poorly specified and they are completely non-portable. See this.

这与位字段无关。这是因为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.

所以你的位域是整数提升为int类型在printf甚至开始解释。标志被保留了下来,所以你看到的是一二的补码int包含价值1进制表示。

作为一个侧注,我不建议你使用比特字段,因为他们的行为是不明确的,他们是完全非便携式。看到这个。

answer4: 回答4:

Your system (and almost all) systems stores negative numbers in 2's complement form. -1 is represented as FFH in 8-bit 2's complement form.

What you are observing is sign extended 2's complement of '-1'.

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

你正在观察的是符号扩展2的“- 1”的补充。

answer5: 回答5:

%x means that printf will output its value in hexadecimal format. Now, the question is why the output of -1 is looks like ffffffff (0xffffffff).

1 byte means 8 bits, and in hexadecimal, you can fit up to f in 4 bits. So 1 byte can hold maximum value of ff in hexadecimal.

So,

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

Now, -1 is representative as Two's complement, means it is a negative number of 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

So, 0xffffffff is tows complements representation of -1. No magic.

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

1字节的8位,和十六进制,你可以胜任F 4位。所以1字节可以容纳FF十六进制值。

所以,

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

现在,1是代表的两个补码,意思是负数为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 is tows complements representation of -1. No magic.

c  int  hex  bit-fields  negative-number