MISRA Discussion Forums

Full Version: Rule 10.1, Rule 6.5 and Boolean bit-fields
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Is there a MISRA-compliant way to have effectively boolean bit-fields? Single bit-fields can't be signed per Rule 6.5. So the bit-fields must be unsigned. Now we need to pick the signedness of the boolean type.

If we go with
typedef signed int TBool;
then we're going to be violating Rule 10.1 whenever we assign between the unsigned bit-field and the signed boolean type. E.g.:
myFlags.unsignedBit = signedBoolFlag; /* Implicitly converting signed to unsigned */
   signedBoolFlag = myFlags.unsignedBit; /* Implicitly converting unsigned to signed */
If we go with
typedef unsigned int TBool;
then we're going to be violating Rule 10.1 whenever we do something like
unsignedBoolFlag = (c > d); /* Implicitly converting signed to unsigned */
because the boolean expression is technically signed int.

Are boolean bit-fields something that MISRA C is trying to prevent? Are they dangerous? I know I could be using casts, but that gets ugly quickly, and pervasive casts bypass type checking and pretty much defeat the purpose of the MISRA rules in the first place.

One thing I thought of is to define something like
#define ISTRUE(cond) ((cond) ? TRUE : FALSE)
and then I can use
unsignedBoolFlag = ISTRUE(c > d); /* Fine as long as TRUE and FALSE are unsigned */
This may or may not be less efficient than without the ISTRUE() macro, depending on the compiler and optimizations. But it's still ugly.

- Joel
It is correct to assume that any single-bit bit-field must have unsigned int type and it is therefore reasonable to assume that any type used for storing Boolean values must also be unsigned int.

MISRA C introduces the concept of effectively Boolean expressions and gives guidance on when these expressions can and cannot be used. However, the treatment of Boolean values and types in MISRA C is incomplete as your question shows. The rules in Section 10 were designed to be applied to arithmetic types and do not cover plain char, enumerated types, Boolean types or bit-fields.

Firstly, it should be possible to assign the value of an effectively Boolean expression to an object with effectively Boolean type without violating any MISRA rules. Unfortunately, Rule 10.1 is violated in the example you give.

Secondly, it may well be that unsigned char is a better effectively Boolean type than unsigned int. On most implementations an object with unsigned char type will require less storage space than one with unsigned int type. It may also be quicker to access and operate on unsigned char on some implementations. However, the behaviour is undefined in C90 if a bit-field is defined with unsigned char type.

You should have little trouble in justifying a deviation for Rule 10.1 provided that the right-hand side of the assignment is effectively Boolean and the left-hand side is either an unsigned bit-field or has effectively Boolean type. Since the value of the effectively Boolean expression is guaranteed to be 0 or 1 there is no chance of loss of information.

As has been mentioned in earlier postings, e.g. http://www.misra-c2.com/forum/viewtopic.php?f=66&t=265, the MISRA C Working Group is developing a new revision of the MISRA C Guidelines. This version has a full treatment of Boolean values and types and therefore avoids problems such as the one you have identified.
Practically, aren't 1 bit Booleans a rather rare and obscure thing in ISO C compliant code? (They are quite common in non-standard code, but that's irrelevant because of rule 1.1 of MISRA)

Most embedded systems I have seen declare Boolean as a "whole" integer type, where unsigned char would indeed be the most common definition. When the average C programmer has need to do bit manipulations, they do so by using the bitwise operators on a "whole" integer type. MCU register manipulations etc. Many CPUs don't even support bit instructions, but must work on byte level anyway.

Why can't MISRA simply ban bit fields entirely and be done with them? They are a superfluous feature of the C language and incredibly poorly defined by the standard, making them a notable hazard in any safety-critical software, and completely unportable on top of it.
Thank you for the explanation. I wanted to confirm that what I'm doing is both OK with respect to the intent of MISRA, yet also technically a violation the way the rules are currently written. You've confirmed both of those. And I agree that justifying the Rule 10.1 deviation should be no problem.

The issue now becomes more one of telling the rule checker to ignore these assignments. I need a way to prevent the rule checker from reporting these violations, without turning off Rule 10.1 altogether, and without peppering the code with special commands to tell the rule checker that each of the assignments is OK. I think once the rules are updated as you mention, and then once rule checkers are updated accordingly, this becomes a non-issue. But in the mean-time, I've got to deal with it.

I can think of two mechanisms:
unsignedBoolFlag = ISTRUE(c > d);
unsignedBoolFlag = (TBool)(c > d);
I actually think I like the first mechanism, because I can eventually (once MISRA and the rule checker support it) simply search for and remove the ISTRUE macro. If I use the (TBool) cast, then I've basically got a redundant cast, and down the road I can't just "blindly" remove all (TBool) casts, because some may be legitimate.

Also, I can conditionally define the ISTRUE macro to be something like
#define ISTRUE(cond) ((cond) ? TRUE : FALSE)
#define ISTRUE(cond) (cond)
so that my rule checker is happy, but the macro is transparent to the compiler.
MISRA doesn't offer any guidance on how to control checking tool diagnostic messages. Either of your proposals would work and, as you point out, using the ISTRUE macro has some advantages.