Bit Fields in C

3k views Asked by At

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.

5

There are 5 answers

0
Sourav Ghosh On BEST ANSWER

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

0
Vagish On

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

0
Sergey Kalinichenko On

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

0
Lundin On

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.

0
mazhar islam On

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