The C Standard mandates that values of unsigned types which rank below "int", and whose values are within the range of "int", are always promoted to "signed int" when used in expressions. Thus, given something like:
uint8_t a,b;
if ((a-b) > (uint8_t)1) ...
the subtraction and comparison must behave as though all values are converted to
type signed int
. I'm working on a MISRA-C 2004 project, however, with a compiler that's supposed to validate code to that standard, and it appears that MISRA's rules, at least in the 2004 version, are oblivious to such standard promotions.
Of the following expressions, which ones should be valid in MISRA-C 2004, MISRA-C 2012, both, or neither:
if ((a-b) > (uint8_t)1) ... // Accepted by the TI compiler
if ((uint8_t)(a-b) > (uint8_t)1) ... // Accepted by the TI compiler
if ((a-b) > 1u) ... // Accepted by the TI compiler
if ((a-b) > 1) ... // Rejected by the TI compiler
If the TI compiler is accurately reflecting what is required by the MISRA-C 2004 rules, it would seem like the group that wrote those rules expected that C's promotion rules would be different from what C89 required, since the form rejected by the compiler has the same semantics as the first one, while the third form the compiler accepts looks superficially like the first one but has different corner-case behavior, and the second form has yet another different behavior.
Changing all occurrences of uint8_t to uint16_t or uint32_t does not seem to affect which forms are accepted or rejected, but would cause the first acceptable form to have semantics which on some compilers would match the rejected form (as it did with uint8_t), but on other compilers would match the other two accepted forms (which would then have the same semantics as each other).
Is the TI compiler correctly interpreting the requirements of MISRA-2004 in accepting code whose behavior would vary among implementations, and rejecting code whose behavior (in the uint8_t case) would be consistent on all conforming implementations? Have the rules changed in MISRA-C 2012 in a way that would affect the above expressions?
Also, if MISRA-C 2004 would require either pre-casting the operands to the expression or post-casting the result, but the compiler was erroneously accepting the first and third forms, which did neither, in what cases would such casts be required? Does either the 2004 or 2012 edition allow the casts to be omitted in the cases where the authors of C rationale would expect that signedness shouldn't matter (e.g. thus allowing:
uint8_t a,b,c,d;
a=b-c+d;
because even though the expression adds a signed value (b+c) to an object of unsigned type, the result is coerced in such a way that will treat as equivalent all results that are congruent mod 256)?
int
is 8-bit, your compiler has a bug, or your real code has some crucial difference from your snippet. – user2357112 supports Monica