Maybe the concept of composite cast sounds quite weird, so let me clarify it: A composite expression is a non-constant expression which is the direct result of a composite operator.
For example, a composite macro can be defined as follow:
Get_Translated_Aux() returns a uint8 value…so, the today question is: Which is the type of FAN_HYSTERESIS_AUX?
If you said uint8, you are right because C always uses the largest type in a assignment, in this case uint8, which can express larger numbers than sint8 by definition. This selection is called “Integer promotion”.
Integer Promotion is the silent conversion of smaller integral types when an expression is evaluated in an operation. For example:
The answer of the previous code is uint16, “C” will be promoted to be uint16 and then both uint16 will convey to a uint16 result.
Moreover, there is a concept called “Balancing” which is similar than integer promotion, but it takes place when there are two different operands. Balancing will convert both operands to a common type to perform further operations.
The balancing sets of rules are as follow:
- If either operand is long double, the other operand is converted to long double.
- Otherwise, if either operand is double, the other is converted to double.
- Otherwise, if either operand is float, the other is converted to float.
- The integral promotions are performed on both operands
- If either operand is unsigned long int the other is converted to unsigned long int
- Otherwise if one operand is long int, and the other operand is unsigned int:
- If a long int can represent all values of an unsigned int, the unsigned int is converted to long int.
- Otherwise both are converted to unsigned long int
- Otherwise if one operand is long int the other is converted to long int
- Otherwise if either operand is unsigned int the other is converted to unsigned int.
- Otherwise, both operands have type int
So, let’s define an example to make balancing concept easier. In this example, we are going to use FAN_HYSTERESIS_TEMP to compare if an input temperature is in range to turn on an output load:
Remember than FAN_HYSTERESIS_TEMP operands were promoted to uint8, so the first reflection might be to cast the composite expression to sint16 as we might have large temperature values.
This is a bad approach since MISRA Rule 10.6 and 10.7 forbid that a value of a composite expression is used in usual arithmetic conversion and even more being casted to a wider essential type. This is because the sequence of arithmetic operations within an expression must be conducted in the same essential type to avoid confusion to the developer.
Imagine a sequence of arithmetic operations as follow:
u32a + u16b + u16c;
But what if we add a composite expression? The composite expression will make harder to track down the result type. For example, the following composite expression requires an implicit conversion to uint32.
(u16a + u16b ) + u32c
The correct approach is to perform an artificial integer promotion to the same essential type; that is to cast the promoted type (uint8) to an even higher type to force the result to be sint16, and now the conditional does not require any cast:
This code won’t yield to any QAC warning.
- Use composite expression carefully in sequences of arithmetic operations.
- Remember implicit integer and balancing concepts to track down types in composite expressions.
- Avoid explicit and implicit conversions of composite expressions.
- Force artificial casting from the root of the composite expression if a cast is really required.