c++cbit-fieldssigned-integerimplementation-defined-behavior

Why is assigning a value to a bit field not giving the same value back?


I saw the below code in this Quora post:

#include <stdio.h>

struct mystruct { int enabled:1; };
int main()
{
  struct mystruct s;
  s.enabled = 1;
  if(s.enabled == 1)
    printf("Is enabled\n"); // --> we think this to be printed
  else
    printf("Is disabled !!\n");
}

In both C & C++, the output of the code is unexpected,

Is disabled !!

Though the "sign bit" related explanation is given in that post, I am unable to understand, how it is possible that we set something and then it doesn't reflect as it is.

Can someone give a more elaborate explanation?


Note: Both the tags & are required, because their standards slightly differ for describing the bit-fields. See answers for C specification and C++ specification.


Solution

  • As per the C++ standard n4713, a very similar code snippet is provided. The type used is BOOL (custom), but it can apply to any type.

    12.2.4

    4 If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field shall compare equal. If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold all the values of that enumeration type (10.2), the original enumerator value and the value of the bit-field shall compare equal. [ Example:

    enum BOOL { FALSE=0, TRUE=1 };
    struct A {
      BOOL b:1;
    };
    A a;
    void f() {
      a.b = TRUE;
      if (a.b == TRUE)    // yields true
        { /* ... */ }
    }
    

    — end example ]


    At 1st glance, the bold part appears open for interpretation. However, the correct intent becomes clear when the enum BOOL is derived from the int.

    enum BOOL : int { FALSE=0, TRUE=1 }; // ***this line
    struct mystruct { BOOL enabled:1; };
    int main()
    {
      struct mystruct s;
      s.enabled = TRUE;
      if(s.enabled == TRUE)
        printf("Is enabled\n"); // --> we think this to be printed
      else
        printf("Is disabled !!\n");
    }
    

    With above code it gives a warning without -Wall -pedantic:

    warning: ‘mystruct::enabled’ is too small to hold all values of ‘enum BOOL’ struct mystruct { BOOL enabled:1; };

    The output is:

    Is disabled !! (when using enum BOOL : int)

    If enum BOOL : int is made simple enum BOOL, then the output is as the above standard pasage specifies:

    Is enabled (when using enum BOOL)


    Hence, it can be concluded, also as few other answers have, that int type is not big enough to store value "1" in just a single bit bit-field.