Search code examples
c++structurebittype-punning

Bit fetching with type punning. Unexpected behaviour


Expected result

The program simply prints anyNum in its binary representation.
We accomplish this by "front popping" the first bit of value and sending it to standard output. After ≤32 iterations i (=anyNum) will finally fall down to zero. Loop ends.

Problem

The v1 version of this code produces the expected result (111...),
However, in v2, when I used a mask structure to get the first bit, it worked as if the last bit was grabbed (1000...).
Maybe not the last? Anyway why and what is happing in second version of the code?

#include <iostream>

typedef struct{
  unsigned b31:   1;
  unsigned rest:  31;
} mask;

int main()
{  
  constexpr unsigned anyNum= -1; //0b111...
  for (unsigned i= anyNum; i; i<<=1){
    unsigned bit;
    //bit= (i>>31); //v1
    bit= ((mask*)&i)->b31;  //v2 (unexpected behaviour)
    std::cout <<bit;
  }
}

Environment

  • IDE & platform: https://replit.com/
  • Platform: Linux-5.11.0-1029-gcp-x86_64-with-glibc2.27
  • Machine: x86_64
  • Compilaltion command: clang++-7 -pthread -std=c++17 -o main main.cpp

Solution

  • unsigned b31: 1; is the least significant bit.

    Maybe not the last?

    The last.

    why

    Because the compiler chose to do so. The order is whatever compiler decides to.

    For example, on GCC the order of bits in bitfields is controlled with BITS_BIG_ENDIAN configuration options.

    x86 ABI specifies that bit-fields are allocated from right to left.

    what is happing in second version of the code?

    Undefined behavior, as in, the code is invalid. You should not expect the code to do anything sane. The compiler happens to generate code that is printing the least significant bit from i.