Question

I want to declare a bitfield with the size specified using the a colon (I can't remember what the syntax is called). I want to write this:

void myFunction() 
{   
  unsigned int thing : 12;
  ...
}

But GCC says it's a syntax error (it thinks I'm trying to write a nested function). I have no problem doing this though:

struct thingStruct
{
  unsigned int thing : 4;
};

and then putting one such struct on the stack

void myFunction() 
{   
  struct thingStruct thing;
  ...
}

This leads me to believe that it's being prevented by syntax, not semantic issues.

So why won't the first example work? What am I missing?

Was it helpful?

Solution

As others have said, bitfields must be declared inside a struct (or union, but that's not really useful). Why? Here are two reasons.

  • Mainly, it's to make the compiler writer's job easier. Bitfields tend to require more machine instructions to extract the bits from the bytes. Only fields can be bitfields, and not variables or other objects, so the compiler writer doesn't have to worry about them if there is no . or -> operator involved.

  • But, you say, sometimes the language designers make the compiler writer's job harder in order to make the programmer's life easier. Well, there is not a lot of demand from programmers for bitfields outside structs. The reason is that programmers pretty much only bother with bitfields when they're going to cram several small integers inside a single data structure. Otherwise, they'd use a plain integral type.

Other languages have integer range types, e.g., you can specify that a variable ranges from 17 to 42. There isn't much call for this in C because C never requires that an implementation check for overflow. So C programmers just choose a type that's capable of representing the desired range; it's their job to check bounds anyway.

C89 (i.e., the version of the C language that you can find just about everywhere) offers a limited selection of types that have at least n bits. There's unsigned char for 8 bits, unsigned short for 16 bits and unsigned long for 32 bits (plus signed variants). C99 offers a wider selection of types called uint_least8_t, uint_least16_t, uint_least32_t and uint_least64_t. These types are guaranteed to be the smallest types with at least that many value bits. An implementation can provide types for other number of bits, such as uint_least12_t, but most don't. These types are defined in <stdint.h>, which is available on many C89 implementations even though it's not required by the standard.

OTHER TIPS

The first example won't work because you can only declare bitfields inside structs. This is syntax, not semantics, as you said, but there it is. If you want a bitfield, use a struct.

Why would you want to do such a thing? A bit field of 12 would on all common architectures be padded to at least 16 or 32 bits.

If you want to ensure the width of an integer variable use the types in inttypes.h, e.g int16_t or int32_t.

Bitfields provide a consistent syntax to access certain implementation-dependent functionality. The most common purpose of that functionality is to place certain data items into bits in a certain way, relative to each other. If two items (bit-fields or not) are declared as consecutive items in a struct, they are guaranteed to be stored consecutively. No such guarantee exists with individual variables, regardless of storage class or scope. If a struct contains:

struct foo {
  unsigned bar: 1;
  unsigned boz: 1;
};

it is guaranteed that bar and boz will be stored consecutively (most likely in the same storage location, though I don't think that's actually guaranteed). By contrast, 'bar' and 'boz' were single-bit automatic variables, there's no telling where they would be stored, so there'd be little benefit to having them as bitfields. If they did share space with some other variable, it would be hard to make sure that different functions reading and writing different bits in the same byte didn't interfere with each other.

Note that some embedded-systems compilers do expose a genuine 'bit' type, which are packed eight to a byte. Such compilers generally have an area of memory which is allocated for storing nothing but bit variables, and the processors for which they generate code have atomic instructions to test, set, and clear individual bits. Since the memory locations holding the bits are only accessed using such instructions, there's no danger of conflicts.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top