cgcccomparisonsignedunsigned-integer

Is 0u defaulting to a signed int?


The following code triggers a signed unsigned comparison warning:

uint16 x = 5;
if(((x) & (uint16)0x0001u) > 0u) {...}

Replacing the if with this eliminates the warning:

if(((x) & (uint16)0x0001u) > (uint8)0u) {...} //No warning

Shouldn't 0u become an unsigned integer and not trigger this warning to begin with?


Solution

  • Everything in C has a type and that includes integer constants such as 0 and 0u.

    In the original expression without any casts ((x & 0x0001u) > 0u):

    Then x is type uint16_t, 0x0001u is type unsigned int (because of the u) and 0u is also unsigned int.

    From there, the usual arithmetic conversions which includes integer promotion apply (see Implicit type promotion rules). On a 32 or 64 bit system which this is (TriCore = 32 bit), the uint16_t is integer promoted to int, since uint16_t is a small integer type (smaller than int).

    Then the left expression ends up with types int & unsigned int. They are then balanced as per "the usual" by making the signed operand unsigned. The final expression ends up with types unsigned int > unsigned int - the same types and an unsigned comparison.


    In case of ((x) & (uint16)0x0001u) > 0u, we end up with the same but now 0x0001u is explicitly forced a conversion down to uint16_t. We end up with types uint16_t & uint16_t. Both operands are now integer promoted to int, but since they are the same type, no further conversions are made. And so the type on the left side of > is int but on the right side it remains unsigned int. And thus "signed vs unsigned comparison".

    (Which is not necessarily an error, but could be. It's brittle and error-prone.)


    In case of (x) & (uint16)0x0001u) > (uint8)0u you force the operands further into different types: (uint16 & uint16_t) > uint8_t. The left side is promoted to int as before, but now uint8_t is integer promoted to int too. So you actually end up with a signed comparison even though all operands were unsigned types. Probably not the intention.


    Good practices:

    When dealing with microcontrollers, MISRA C is highly recommended/industry standard. A large chapter in MISRA is dealing with implicit conversion bugs, so by enforcing the rules there you weed out such bugs.