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

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

%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。

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).

``````#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 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.

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.

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'.

%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
``````

``````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
``````

c  int  hex  bit-fields  negative-number