MISRA Discussion Forums

Full Version: Rule 10.5 clarification
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
The description of rule 10.5 mentions that the operators must be applied to "small integer types" for the casts to be required. The types unsigned char and unsigned short are mentioned explicitly. What if char, short, and int are all the same size on the machine? In that case is OK to not perform the required cast? This really comes down to whether or not we should be checking for the unsigned char and unsigned short types explicitly or instead should check for all types which have a a narrower type than int.
One of the cornerstones of MISRA C is to make sure the C code is fully portable. This is perhaps the biggest concern of MISRA-C, so the rules should be the same no matter machine.

Also, by definition of the C standard's integer promotion rules, unsigned char and unsigned short always have lesser "integer conversion rank" than int, and the type will be converted to int no matter what size char/short have on your machine. Note the danger here: "int", not unsigned int. So there could possibly be a change of signedness.
I don't think the first statement is entirely accurate. There are several rules which pertain to narrower and wider types and so most definitely depend on the implemented size of types for a given machine. For these rules (10.1 for instance) it seems practical to require the code to be rechecked for misra violations using the types defined for that machine.

The issue here is also that some expressions which appear to be compliant will also start to fail. For instance, here is an example from the Exemplar test suite:

typedef int uint16_t;
uint16_t u16r;

u16r = 0x1234U 4; /* Not compliant */

This example is compliant on a machine with a 16 bit int because the underlying type of (u16a
Integer constants can never be unsigned char or unsigned short.

ISO C 9899:1999 6.4.4.1:
Code:
Suffix      Octal or Hexadecimal Constant    

None        int
            unsigned int
            long int
            unsigned long int

u or U      unsigned int  
            unsigned long int

The smallest unsigned integer type (underlying type) in your first code example is uint16_t. As you can see by the standard cited above, it can never be unsigned char or unsigned short.

And yes, by rule 10.5 you must immediately cast the result into this operand in case uint16_t happens to be unsigned short. In that case, the integer promotions will jump in and possibly change signedness of the final expression. Again, this depends on "integer conversion rank" in the C standard, and not on the implemented size of unsigned short.

But if one typedef uint16_t as unsigned int, no cast is necessary. As you point out, that will however lead to portability issues on 32-bit machines. This is perhaps one of the biggest flaws in the C language, and there is really no perfect work-around.

Good practice is to keep the typedefs for integers in a separate header file, which has to be rewritten for each platform you port the code to.
Lundin Wrote:Integer constants can never be unsigned char or unsigned short.
In the C standard, yes constants can never be char or short. However, a constants fundamental type can char or short if that is the smallest type that is capable of representing its value.

Lundin Wrote:And yes, by rule 10.5 you must immediately cast the result into this operand in case uint16_t happens to be unsigned short. In that case, the integer promotions will jump in and possibly change signedness of the final expression. Again, this depends on "integer conversion rank" in the C standard, and not on the implemented size of unsigned short.
If unsigned short and unsigned int are the same size, how will the signedness of the final expression change? The unsigned short will be promoted to unsigned int because int cannot represent the entire range of values representable by unsigned short. Besides, this rule is only concerned with higher order bits showing up when the user didn't expect it, and this won't happen if short and int are the same size.
By your rationale, you are inferring, from rule 10.5, that all objects of user defined types should be immediately cast just in case they are smaller than an int. It is perfectly legal to have a uint32_t be an unsigned short. If that is the intention, then the rule should be something like "always cast every result of the ~ and
c-addison Wrote:"The description of rule 10.5 mentions that the operators must be applied to "small integer types" for the casts to be required. The types unsigned char and unsigned short are mentioned explicitly. What if char, short, and int are all the same size on the machine? In that case is OK to not perform the required cast? This really comes down to whether or not we should be checking for the unsigned char and unsigned short types explicitly or instead should check for all types which have a narrower type than int.

Lundin Wrote:"One of the cornerstones of MISRA C is to make sure the C code is fully portable. This is perhaps the biggest concern of MISRA-C, so the rules should be the same no matter machine."




The primary aim of MISRA C is to promote "safety" – portability is a secondary concern. Reliance on implementation defined behaviour can compromise safety and should therefore be avoided wherever possible.

The intention of Rule 10.5 is two-fold:
  • a) to eliminate implementation defined behaviour
    b) to eliminate reliance on integral promotion - an aspect of C which is confusing and rarely understood

There is a case for suggesting that Rule 10.5 should be applied to operands of any type, and not simply to operands with an underlying type which is a "small integer type". This is something that will be considered for a future release of the MISRA C Guidelines.

Lundin Wrote:"Also, by definition of the C standard's integer promotion rules, unsigned char and unsigned short always have lesser "integer conversion rank" than int, and the type will be converted to int no matter what size char/short have on your machine. Note the danger here: "int", not unsigned int. So there could possibly be a change of signedness."

This statement is not correct. Operands of type unsigned char and unsigned short will only undergo integral promotion to signed int if the types are "smaller" than type int. If char, short and int are all implemented in the same number of bits, unsigned char and unsigned short will be promoted to unsigned int.

c-addison Wrote:"Now what happens is that on this machine 0x1234U can technically be either an unsigned char, unsigned short, or an unsigned int. >From the misra spec, we chose the "smallest unsigned integer type that is capable of representing its value", unsigned char. So in this case the underlying type of the expression is unsigned char but the underlying type of u16r is unsigned int, therefore a diagnostic is issued. If instead of explicitly checking for unsigned char or unsigned short, we check the size of the types, then the problem goes away."

If char, short and int are all implemented in the same size, either one of them could be described as "the smallest integer type" (although char is always the type of lowest rank). There is no violation of Rule 10.5 here.

[quote="c-addison"]
"Another example of where the size of an int matters is the following case:
typedef int uint16_t;
uint16_t u16r, u16a;
u16r = ( u16a > 4; /* Not compliant */

This example is compliant on a machine with a 16 bit int because the underlying type of (u16a