14

So I recently came across something like this

unsigned char ch : 7;

inside a struct. I read about it a little. Apparently these are called bit fields. They are used to set the width of data that a char can receive. But how do we use these things. For example, I know that we can set variable ch to be a byte

unsigned char ch = 0x61;
cout << ch << endl;

This will output

a

However, what do we do with the bitfields?

unsigned char ch : 7;
ch = 0x61;                //This doesn't work for some reason

unsigned char ch : 7;
unsigned char ch = 0x61/  //Neither does this.

Thanks for the help

Jason C
  • 38,729
  • 14
  • 126
  • 182
Q_A
  • 433
  • 2
  • 6
  • 14

1 Answers1

24

Bitfields can only be used inside structured data types, i.e. struct, class, and union types. The purpose is to allow you to pack multiple members inside a single byte, without having to write lots of explicit shifts and masks. For instance, you can write:

struct halfbyte_t {
    unsigned int half1: 4;
    unsigned int half2: 4;
} halfbyte;

This declares a variable named halfbyte that contains two 4-bit members, which will be packed into a single 8-bit byte, rather than having to use 2 bytes if you just declared them unsigned char.

You access them just like any other structure member:

halfbyte.half1 = 3;
cout << halfbyte.half3;

1-bit fields are especially useful if you have lots of boolean flags in a structure, since you don't have to have a separate byte for each flag.

struct flag_t {
    unsigned int flag1: 1;
    unsigned int flag2: 1;
    unsigned int flag3: 1;
    unsigned int flag4: 1;
    ...
};
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thanks. that was a good explanation. I have a follow-up question though. When you said that the two halfbytes could be packed into an 8-bit character, How exactly would I do that? – Q_A Mar 08 '16 at 01:26
  • @Q_A The most portable and semantically correct would be with arithmetic, e.g. `(half1 << 4) | half2` or the other way around. You could hack it with unions or reinterpret casts, but the results won't always be consistent. See also http://stackoverflow.com/questions/19376426/order-of-fields-when-using-a-bit-field-in-c. The main usage is for saving space in memory constrained environments. If you find you often need to combine their values then you might reconsider using bit fields; really they're for things that are semantically separate. – Jason C Mar 08 '16 at 01:29
  • @Q_A You don't do it, it's done automatically by the compiler. That's the whole point. – Barmar Mar 08 '16 at 01:30
  • 1
    The layout of bit-fields is non-portable, so they are of limited use if you are trying to write portable code – M.M Mar 08 '16 at 01:57
  • 6
    @M.M that's a sweeping statement and more FUD sans an explanation of "*limited*": code can portably use them for the functionality described in this answer, they're just not portable usable in raw binary I/O - but the same can be said of e.g. `int` due to endianness and the variety of encodings (sign magnitude, 2s complement...). – Tony Delroy Mar 08 '16 at 05:00
  • Do people use bit fields of size 1 for individual flags? That is, instead of defining, say, 16 const unsigned ints and performing the typical bit manipulation and testing algebra, I define a struct with 16 bit fields and use them like normal members, essentially? (I think I never need to test for "none set" in my use case.) – Peter - Reinstate Monica Jan 04 '23 at 23:50
  • @Peter-ReinstateMonica Your method has the advantage that the values are portable, so it's very common when defining protocols and file data formats. The layout of bit fields is implementation-dependent, so it's only useful for data structures used internally. – Barmar Jan 05 '23 at 16:30