Bit fields are specified numbers of bits that may or may not have an associated identifier. Bit fields offer a way of subdividing structures (structs, unions, classes) into named parts of user-defined sizes.
Declaring bit fields
You specify the bit-field width and optional identifier as follows:
type-specifier <bitfield-id> : width;
In C++, type-specifier is bool, char, unsigned char, short, unsigned short, long, unsigned long, int, unsigned int, __int64 or unsigned __int64. In strict ANSI C, type-specifier is int or unsigned int.
The expression width must be present and must evaluate to a constant integer. In C++, the width of a bit field may be declared of any size. In strict ANSI C, the width of a bit field may be declared only up to the size of the declared type. A zero length bit field skips to the next allocation unit.
If the bit field identifier is omitted, the number of bits specified in width is allocated, but the field is not accessible. This lets you match bit patterns in, say, hardware registers where some bits are unused.
Bit fields can be declared only in structures, unions, and classes. They are accessed with the same member selectors ( . and ->) used for non-bit-field members.
Limitations of using bit fields
When using bit fields, be aware of the following issues:
#define Nothing 0x00
#define bitOne 0x01
#define bitTwo 0x02
#define bitThree 0x04
#define bitFour 0x08
#define bitFive 0x10
#define bitSix 0x20
#define bitSeven 0x40
#define bitEight 0x80
can be used to write code like:
if (flags & bitOne) {...} // is bit One turned on flags |= bitTwo; // turn bit Two on flags &= ~bitThree; // turn bit Three off
Similar schemes can be made for bit fields of any size.
Padding of bit fields
In C++, if the width size is larger than the type of the bit field, the compiler will insert padding equal to the requested width size minus the size of the type of the bit field. So, declaration:
struct mystruct { int i : 40; int j : 8; };
will create a 32 bit storage for 'i', an 8 bit padding, and 8 bit storage for 'j'. To optimize access, the compiler will consider 'i' to be a regular int variable, not a bit field.
Layout and alignment
Bit fields are broken up into groups of consecutive bit fields of the same type, without regard to signedness. Each group of bit fields is aligned to the current alignment of the type of the members of the group. This alignment is determined by the type AND by the setting of the overall alignment (set by the byte alignment option –aN). Within each group, the compiler will pack the bit fields inside of areas as large as the type size of the bit fields. However, no bit field is allowed to straddle the boundary between 2 of those areas. The size of the total structure will be aligned, as determined by the current alignment.
Example of bit field layout, padding, and alignment
In the following C++ declaration, my_struct contains 6 bit fields of 3 different types, int, long, and char:
struct my_struct { int one : 8; unsigned int two : 16; unsigned long three : 8; long four : 16; long five : 16; char six : 4; };
Bit fields 'one' and 'two' will be packed into one 32-bit area.
Next, the compiler inserts padding, if necessary, based on the current alignment, and the type of three, because the type changes between the declarations of variables two and three. For example, if the current alignment is byte alignment (-a1), no padding is needed; whereas, if the alignment is 4 bytes (-a4), then 8-bit padding is inserted.
Next, variables three, four, and five are all of type long. Variables three and four are packed into one 32 bit area, but five can not be packed into that same area, since that would create an area of 40 bits, which is more than the 32 bit allowed for the long type. To start a new area for five, the compiler would insert no padding if the current alignment is byte alignment, or would insert 8 bits of padding if the current alignment is dword (4 byte) alignment.
With variable six, the type changes again. Since char is always byte aligned, no padding is needed. To force alignment for the whole struct, the compiler will finish up the last area with 4 bits of padding if byte alignment is used, or 12 bits of padding if dword alignment is used.
The total size of my_struct is 9 bytes with byte alignment, or 12 bytes with dword alignment.
To get the best results when using bit fields you should:
Using one bit signed fields
For a signed type of one bit, the possible values are 0 or –1. For an unsigned type of one bit, the possible values are 0 or 1. Note that if you assign “1” to a signed bit field, the value will be evaluated as –1 (negative one).
When storing the values true and false into a one bit sized bit field of a signed type, you can not test for equality to true because signed one bit sized bit fields can only hold the values '0' and '-1', which are not compatible with true and false. You can, however, test for non-zero.
For unsigned varieties of all types, and of course for the bool type, testing for equality to true will work as expected.
Thus:
struct mystruct { int flag : 1; } M; int testing() { M.flag = true; if(M.flag == true) printf("success");}
will NOT work, but:
struct mystruct { int flag : 1; } M; int testing() { M.flag = true; if(M.flag) printf("success"); }
works just fine.
Notes on compatibility
Between versions of the compiler, changes can be made to default alignment, or for purposes of compatibility with other compilers. Consequently, this could change the alignment of bit fields. Therefore, there is no guarantee that the alignment of bit fields will be consistent between versions of the compiler. To check the backward compatibility of bit fields in your code you can add an assert statement that checks for the structure size you are expecting.
According to the C and C++ language specifications, the alignment and storage of bit fields is implementation defined. Therefore, compilers can align and store bit fields differently. If you want complete control over the layout of bit fields, it is advisable to write your own bit field accessing routines and create your own bit fields.
Copyright(C) 2008 CodeGear(TM). All Rights Reserved.
|
What do you think about this topic? Send feedback!
|