This is the sixth in a series of tips on writing effective C. Today I’m going to address the topic of creating what I call a flags variable. A flags variable is nothing more than an integral type that I wish to treat as an array of bits, where each bit represents a flag or boolean value. I find these particularly valuable in three situations:
- When the CPU has part of its address space that is much faster to access than other regions. Examples are the zero page on 6805 type processors, and the lower 256 bytes of RAM on AVR processors. Depending upon your compiler, you may also want to do this with the bit addressable RAM region of the 8051.
- When I’m running short on RAM and thus assigning an entire byte or integer to store a single boolean flag is waste I can’t afford.
- When I have a number of related flags where it just makes sense to group them together.
The basic approach is to use bitfields. Now I’m not a huge fan of bitfields – particularly when someone tries to use them to map onto hardware registers. However, for this application they work very well. As usual however, the devil is in the details. To show you what I mean, I’ll first show you a typical implementation of mine, and then explain what I’m doing and why.
typedef union
{
uint8_t all_flags; /* Allows us to refer to the flags 'en masse' */
struct
{
uint8_t foo : 1, /* Explanation of foo */
bar : 1, /* Explanation of bar */
spare5 : 1, /* Unused */
spare4 : 1, /* Unused */
spare3 : 1, /* Unused */
spare2 : 1, /* Unused */
spare1 : 1, /* Unused */
spare0 : 1; /* Unused */
};
} EX_FLAGS;
static EX_FLAGS Flags; /* Allocation for the Flags */
Flags.all_flags = 0U; /* Clear all flags */
...
Flags.bar = 1U; /* Set the bar flag */
There are several things to note here.
Use of a union
The first thing to note is that I have used a union of an integral type (uint8_t) and a structure of bitfields. This allows me to access all the flags ‘en masse’. This is particularly useful for clearing all the flags as shown in the example code. Note that our friends at MISRA disallow unions. However, in my opinion, this is a decent example of where they make for better code – except see the caveat below.
Use of integral type
Standard C requires that only types int and unsigned int may be used for the base type of an integer bitfield. However, many embedded systems compilers remove this restriction and allow you to use any integral type as the base type for a bitfield. This is particularly valuable on 8-bit processors. In this case I have taken advantage of the language extension to use a uint8_t type.
Use of an anonymous structure
You will note that the bitfield structure is unnamed, and as such is an anonymous structure. Anonymous structures are part of C++ – but not standard C. However, many C compilers support this construct and so I use it as I feel it makes the underlying code a lot easier to read.
Naming of unused flags
If you look at the way I have named the unused flags, it looks a little odd. That is the first unused flag is spare5, the next spare4 and so on down to spare0. Now I rarely do things on a whim, and indeed this is a good example. So why do I do it this way? Well, there are two reasons:
- When I first create the structure, I label all the flags, starting from spare7 down to spare0. This inherently ensures that I name precisely the correct number of flags in the structure. To see why this is useful, take the above code and allocate an extra flag in the bitfield structure. Then compile and see if you get a compilation error or warning. Whether you will or not depends upon whether your compiler allows bitfields to cross the storage unit boundary. If it does, then your compiler will allocate two bytes, and the all_flags member of the union will not cover all of the flags. This can come as a nasty surprise (and perhaps explains why MISRA is wary of unions). You can prevent this from happening by naming the flags as shown.
- When it becomes necessary to allocate a new flag, I simply replace the topmost unused flag (in this example that would be spare5) with its new name, e.g. zap. The remainder of the structure is unchanged. If instead I had named the topmost unused flag ’spare0′, the next ’spare1′ and so on, then the code would give a completely misleading picture of how many spare bits are left for future use after I had taken one of the unused flags.
If you look at what I have done here, it’s interesting to note that I have relied upon two extensions to standard C (which violates the MISRA requirement for no use of compiler extensions) and I have also violated a third MISRA tenet via the use of a union. I would not be surprised if I’ve also violated a few other rules as well. Now I don’t do these things lightly, and so I only use this construct when I see real benefit in doing so. I’ll leave it for another day to discuss my overall philosophy regarding adherence to the MISRA guidelines. It is of course up to you the reader to make the determination as to whether this is indeed effective C.
Next Tip
Previous Tip
Home
One problem I recall with C bitfields is that the order of the bits is unspecified. That causes problems when trying to map onto a hardware register, and it causes problems if you use multiple compilers (for a library and a calling application for example)
Couldn't agree more. I never use bitfields to map onto hardware for this very reason. I've noticed that some compiler vendors are getting wise to this problem, and allow you to specify as a compilation switch, in which order the bits should be assigned. Nevertheless until this is mandated, it's safest to just eschew using bitfields to map onto HW.
Having been bitten by bitfield-handling differences when porting a microcontroller design to a new silicon/compiler combination, I would be extremely wary of this approach. In this particular design the engineer concerned had used bitfields to set/clear flag bits in status bytes reported to a host microprocessor. And of course when the design was ported as a 'drop-in' replacement onto new silicon, the system communications stopped working as a result. I guess this is another case (along with the hardware registers mentioned above) where bitfields probably shouldn't be used at all.I have to agree that the bitfield approach results in very readable code, but the expense is that you're at the mercy of your compiler vendor. As K&R points out, "Almost everything about fields is implementation-dependent".To expand on one point Nigel mentions, if you're using the IAR compiler on AVRs, you can declare flag bytes as __regvars to put them into system registers at the bottom of RAM. As he points out, this results in single opcode accesses to set/clear individual bits, giving you smaller and faster code.
Nicely put Alan. This is definitely one of those areas where you don't get something for free.
Hi Nigel, Excellent post that. I have myself used bitfields exactly as you have mentioned, however I admit I have been bitten by porting issues in particular by the ordering of the flag bits.Hence as the old saying goes – once bitten twice…cautious, I am more careful with this particular construct. But the material is very lucid in its content and I wish I had read your blog when I was learning about bitfields. However I am writing to ask your opinion about MISRA C compliance. This is the first time a client company has asked us for MISRA C compliance and I am not quite sure where to start. I started reading the guidelines from the web, however soon realised that its an enormous task and I would never get through all of them. So what I would like to know from you is how realistic is it to expect to comply with all the guidelines? Since my compiled code size is less than 2KB so should we even bother with MISRA C compliance?Your valuable insights would be highly appreciated. Warm RegardsAnand
Anand:You ask some very profound questions, the answers to which are better given in a blog posting, rather than the comments section. I will endeavor to post something within the next day or so. Thanks for commenting.
While your intentions are good, I would advise against using bitfields. Many compilers (e.g. gcc) generate very poor code for accessing them, probably negating anything gained from the denser packing.Instead, I suggest using a variable (or array) of a standard integral type, and defining a few macros to access individual bits. If more than 8 flags are needed, use a type matching the native word size or, if accesses are scattered, the memory bus width if smaller than the word size.GCC will reload the same memory each time a different flag is requested, even it it is already held in a register.