62

What does the following C++ code mean?

unsigned char a : 1; 
unsigned char b : 7;

I guess it creates two char a and b, and both of them should be one byte long, but I have no idea what the ": 1" and ": 7" part does.

M.M
  • 138,810
  • 21
  • 208
  • 365
derrdji
  • 12,661
  • 21
  • 68
  • 78

3 Answers3

73

The 1 and the 7 are bit sizes to limit the range of the values. They're typically found in structures and unions. For example, on some systems (depends on char width and packing rules, etc), the code:

typedef struct {
    unsigned char a : 1;
    unsigned char b : 7;
} tOneAndSevenBits;

creates an 8-bit value, one bit for a and 7 bits for b.

Typically used in C to access "compressed" values such as a 4-bit nybble which might be contained in the top half of an 8-bit char:

typedef struct {
    unsigned char leftFour  : 4;
    unsigned char rightFour : 4;
} tTwoNybbles;

For the language lawyers amongst us, the 9.6 section of the C++11 standard explains this in detail, slightly paraphrased:


Bit-fields [class.bit]

A member-declarator of the form

     identifieropt   attribute-specifieropt   :   constant-expression

specifies a bit-field; its length is set off from the bit-field name by a colon. The optional attribute-specifier appertains to the entity being declared. The bit-field attribute is not part of the type of the class member.

The constant-expression shall be an integral constant expression with a value greater than or equal to zero. The value of the integral constant expression may be larger than the number of bits in the object representation of the bit-field’s type; in such cases the extra bits are used as padding bits and do not participate in the value representation of the bit-field.

Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit.

Note: bit-fields straddle allocation units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others. - end note

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Strictly speaking, in pure C they wouldn't be used with `unsigned char`. C only allows `int`, `signed int` and `unsigned int` in bitfield declarations. C99 adds `_Bool`. `unsigned char` is not a legal type for bitfield in C. – AnT stands with Russia Oct 22 '09 at 05:07
  • That's an implementation issue, at least in c1x: 6.7.2.1 para4 A bit-field shall have a type that is a qualified or unqualified version of \_Bool, signed int, unsigned int, or *some other implementation-defined type*. – paxdiablo Oct 22 '09 at 05:30
  • 1
    @paxdiablo: Yes, but the "some other implementation-defined type" bit is really redundant, because implementation is always allowed to extend the language in any way it sees fit, without an explicit permission in the specific section of the standard. A C implementation can compile Pascal and Fortran code within C code - nobody prohibits it from doing that. Yet, it would be strange to discus Fortran code as possibly valid C code for that reason. The same applies to that "implemenation-defined type" as well. – AnT stands with Russia Oct 22 '09 at 06:04
  • @AndreyT : yet, this kind of wording is quite common; it notes common, reasonable extensions. – MSalters Oct 22 '09 at 09:23
  • Your example does **not** create an 8-bit value. It creates a struct containing a 1-bit and a 7-bit value. It might insert padding between them (and afaik, MSVC does just that) – jalf Oct 22 '09 at 09:33
  • @jalf, that's a *typical* use and likely to be forced by something like #pragma pack. You're right that it *may* not create an 8-bit value in the absence of other information, you are wrong that it *does* not. – paxdiablo Oct 22 '09 at 09:44
  • 4
    @AndreyT, the "implementation-defined type" bit isn't quite redundant here. If it weren't for this, the compiler would be required to give a diagnostic, because of a constraint violation. The "implementation-defined type" thing grants the compiler acceptance of other types without giving a diagnostic. – Johannes Schaub - litb Oct 22 '09 at 10:51
  • @jalf: No, MSVC will not insert padding here. MSVC inserts padding (or, more precisely, switches to a new allocation unit) whenever the declared type changes. As long as the type remains the same, MSVC will continue to fill the last unit until it is full. – AnT stands with Russia Oct 22 '09 at 14:16
  • @litb: Good point. I missed this detail somehow. Yet, I'd still defend my original comment, where by "pure C" I meant "the abstract canonical general-case C". – AnT stands with Russia Oct 22 '09 at 14:18
9

I believe those would be bitfields.

Azeem.Butt
  • 5,855
  • 1
  • 26
  • 22
  • 13
    Not sure, unless it's the brevity or uncertainty but here's an upvote since (1) you're technically correct; and (2) to share the love around :-) – paxdiablo Oct 22 '09 at 04:19
1

Strictly speaking, a bitfield must be a int, unsigned int, or _Bool. Although most compilers will take any integral type.

Ref C11 6.7.2.1:

A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type.

Your compiler will probably allocate 1 byte of storage, but it is free to grab more.

Ref C11 6.7.2.1:

An implementation may allocate any addressable storage unit large enough to hold a bit- field.

The savings comes when you have multiple bitfields that are declared one after another. In this case, the storage allocated will be packed if possible.

Ref C11 6.7.2.1:

If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined.

evaitl
  • 1,365
  • 8
  • 16