3

I have been looking at this code for a while. I know that the output is 50 but am unsure how this occurs.

struct
{ 
    unsigned m : 3;
    unsigned n : 5;
} b;

int main(void)
{ 
    b.m = 2;
    b.n = 6;

    printf("%d", b);
}

Any help someone can offer, I would really appreciate it.

guy25
  • 31
  • 1
  • 3
  • 1
    This invokes **undefined behaviour** - anything could happen. – Oliver Charlesworth Mar 06 '16 at 23:46
  • Thats what i was thinking. This is a practice question for an exam I have coming up so apparently it is supposed to do something. I am only supposed to answer with the output – guy25 Mar 06 '16 at 23:49
  • Ok, but do bear in mind that the practice paper is wrong, then (unless the expected answer is "undefined behaviour"...) – Oliver Charlesworth Mar 06 '16 at 23:52
  • so why, if i actually compile and run this code. it outputs 50?? – guy25 Mar 07 '16 at 00:02
  • You havent told us what programming language and platform you are talking about. For C99 the result can be exlained with a specific compiler behaviour (packing adjanct bitfields on integer boundary with LSB first) but it is not guranteed to work - as other comments said, in C this is called undefined behaviour and it would be an error to ask about it in a quiz. It depends on the compiler and the hardware what the result is (50 is only most likely) – eckes Mar 07 '16 at 22:51

1 Answers1

1

Well, it seems that a struct with consecutive bitfields gets compacted and when is passed to printf with the %d format specifier, this manifests like some kind of "bit aggregation" (see Note). After some testing with different values and such, I came up with the following scheme :

The struct members (bitfields) are aligned thusly:

n n n n n m m m

ie in "descending" order - last comes first.

Then, in main, b.m gets the value 2 which in binary is 10 and in 3-digit format is 010, and b.n gets the value 6 which in binary is 110 and in 5-digit format is 00110, so you end up with 00110010 which has a dec value of ... 50.


To further test this hypothesis I expanded the b struct with one more member and checked if it still holds:

#include <stdio.h>

struct { 
    unsigned m : 3;
    unsigned n : 5;
    unsigned o : 5;
} b;

int main(void) {
    b.m = 1;
    b.n = 1;
    b.o = 1;
    printf("%d\n",b);
    return 0;
}

According to the hypothesis the struct members should be aligned this way:

o o o o o n n n n n m m m

and with the values assigned to them in main (ie 1, 1 and 1) this should result to the binary 0000100001001 which in dec is 265.

Compiling and running yields:

$ gcc -Wall -o stprint stprint.c
stprint.c: In function ‘main’:
stprint.c:13:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct <anonymous>’ [-Wformat=]
     printf("%d\n",b);
     ^
$ ./stprint
265

ie a result that (most probably) verifies the hypothesis. Hope I shed some light on this behavior.


Edit/Note: In case it is not clear from the above, as other commenters pointed out, this behavior depends on the implementation, meaning that it is up to the compiler to decide if this "bit aggregation" takes place or not, and what is the specific order. One has also to take into account the endianness of the underlying platform (see here for example) For this post gcc version 4.8.4 was used in a Ubuntu system.

Community
  • 1
  • 1
sokin
  • 824
  • 2
  • 13
  • 20
  • Yes, multiple adjacent bit fields are usually packed together (although this behavior is implementation-defined): It is implementation specific if theyare and if they are packed from left to right or the other way around. Source: http://en.cppreference.com/w/cpp/language/bit_field – eckes Mar 07 '16 at 22:49
  • @eckes Yes, that goes without saying. That is why I referred to this as a "scheme" and a hypothesis; nothing definite here. The idea of this post was to give a "kickstart" into thinking bitfield-wise when trying to decipher a strange behavior. In this case it was a "descending" order; in others might not. Thanks for the link BTW. – sokin Mar 07 '16 at 23:09