Question

Can anyone explain the output , how the value is stored and calculated?

#include<stdio.h>
struct bitfield
{
    unsigned f1:1;
    unsigned f2:2;
    unsigned   :3;
    unsigned f4:4;
    unsigned f5:5;
    unsigned f6:6;
    unsigned f7:1;
    unsigned f8:8;
} bf;

main()
{
    bf.f1 = 1;
    bf.f2 = 0x3;
    bf.f4 = 0xff;
    bf.f5 = -4;
    bf.f6 = 0377;
    printf("%d %d %d %d %d %d", bf.f1, bf.f2, bf.f4, bf.f5, bf.f6, bf.f8);
}

Output: 1 3 15 28 63 0

Was it helpful?

Solution 3

unsigned fx:n; // Only use the least significant n bits.

               //                        Binary    Decimal
bf.f1 = 1;     // 1    == [0000 0001]:1   == 1      == 1
bf.f2 = 0x3;   // 0x3  == [0000 0011]:2   == 11     == 3
bf.f4 = 0xff;  // 0xff == [1111 1111]:4   == 1111   == 15
bf.f5 = -4;    // -4   == [0xfffffffc]:5  == 11100  == 28
bf.f6 = 0377;  // 0377 == [1111 1111]:6   == 111111 == 63

OTHER TIPS

Very short rundown.

First, bf is an uninitialised global variable. This means it will end up in the .bss segment, which is typically zero-initialised on startup (although you can pass -fno-zero-initialized-in-bss to GCC to stop this, not sure about MSVC, and of course it depends on your crt0). This explains the value of f8, since you haven't written to it.

f1 is 1. You assign it 1. That one's obvious. Same with f2 (since hex 3 is dec 3).

f4 is because the field for f4 is only 4 bits wide. 0xFF is an 8 bit pattern which is all ones, which is then truncated to 4 bits, and is hence 15 (the highest value that can be represented with 4 bits).

f5 is due to a signed/unsigned conversion. The 5-bit two's compliment representation of -4 is 11100. If you interpret that value as unsigned (or rather, just a plain binary -> decimal conversion), you get 28.

f6 is 63 because of an octal conversion. Any C literal number beginning with a zero is treated as octal. Octal 377 is decimal 255 (which is 11111111 in 8-bits), which is then truncated to 6 bits, leaving 111111. This is 63.

Values are stored in the field you specify. However, since in some cases, e.g bf.f4 = 0xff;, the value doesn't fit, it will be losing the upper bits, hence it prints 15 (0x0F). Similarly for -4 stored in f5 -4 = 0xFFFFFFFC as a 32-bit integer, but when stored as an unsigned 5-bit integer, it becomes 0x1C, or 28. The same principle applies to f6.

There is also 3 bit "gap" using an unnamed member between f2 and f4.

Internally, the compiler will do this by using AND, SHIFT and OR operations.

Note that we can't know if f1 is the highest or the lowest bit of the whole value that the fields are stored in. This is something that the compiler implementation will decide on - as long as it's done the same way every time.

unsigned f1:1;           // 1 bit is allocated. 
bf.f1=1;                 // you are storing 1 works fine.

unsigned f2:2;           // 2 bit is allocated.
bf.f2=0x3;               // 3 == '11' in binary so 2 bits are enough so when you print 3 is printed.

unsigned   :3;

unsigned f4:4;          // 4 bit is allocated.
bf.f4=0xff;             // ff is represented as 1111 1111 in binary, 
// but only 4 bits are allocated so only f which is 1111 
// in binary gets stored in this. when you print using %d, 15 is getting printed.


unsigned f5:5;         // 5 bits are allocated
bf.f5=-4;              // -4 in binary for 5 bits is 11100 but you are printing it as %d so it will print 28. and so on...

hope this will help.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top