简体   繁体   中英

Understanding Bit Fields packing in C++

I am trying to understand bitfields.The following example appears in C++ online docs .

#include <iostream>
struct S {
// will usually occupy 2 bytes:
// 3 bits: value of b1
// 2 bits: unused
// 6 bits: value of b2
// 2 bits: value of b3
// 3 bits: unused
unsigned char b1 : 3, : 2, b2 : 6, b3 : 2;
};
int main()
{
    std::cout << sizeof(S) << '\n'; // usually prints 2
}

What I don't understand about this example is that in the comments above the code it is said that after b1:3 there are 2 bits unused.And then after b3:2 there are 3 bits unused.Why?Shoudn't that be the number of bits in unsigned char type - defined bits?Or number of unsued bits left to the next allocation unit boundary?

Packing all of the field declarations onto a single line makes it a little difficult to see what's going on. Here's the same thing, but reformatted:

struct S {
  unsigned char b1:3;  // 3 bits - b1
  unsigned char   :2;  // 2 bits - unused
  unsigned char b2:6;  // 6 bits - b2
  unsigned char b3:2;  // 2 bits - b3
                       // Total: 13 bits
};                     // 3 bits - unused (implicit padding)

The two "unused" sections are: (1) the unnamed field after b1 with an explicit width of 2 bits; and (2) the padding at the end of the struct to round it out to 16 bits (the next unsigned char unit).

I disagree with the documentation you are reading. To quote from the C++ standard "Allocation of bit-fields within a class object is implementation-defined".

Some compilers expand bit fields. If you do

unsigned x : 3 ;

The compiler can do pretty much anything it wants for allocation. I've some compilers that take

unsigned x : 1 ;

and turn it into a 32 bit integer (gives best performance).

You are dealing with material that is just plain wrong. If you want to work with actual bits you either:

1) Need to know exactly how your compiler does the layout; or 2) Use bit masks and the <<, &, |, >> operators to extract and insert values into integers of a known size.

You're dealing with unnamed variables . This will be easier to understand:

#include <iostream>
struct S {
    // will usually occupy 2 bytes:
    // 3 bits: value of b1
    // 2 bits: unused
    // 6 bits: value of b2
    // 2 bits: value of b3
    // 3 bits: unused
    unsigned char b1 : 3;
    unsigned char : 2; // How do you reference these?
    unsigned char b2 : 6, b3 : 2;
};
int main()
{
    std::cout << sizeof(S) << '\n'; // usually prints 2
}

http://ideone.com/6eCUB0

The unnamed ones are variables without a name and thus they can't be referenced in the normal way. At the end of the day, in your case, they just eat up some space and might be used for padding reasons, alignment reasons or anything else that suits this sample.

If you sum all those bits up you'll have 16 which is exactly 2 bytes on most systems. By the way as you can read the " usually " word in the comment is placed with a reason.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM