Muhammad Ali
Muhammad Ali

Reputation: 11

Why "(uint8)0U" appears to the static code analysis tool as a signed operand?

When I run static code analysis it says:

Bitwise operator "~" has a signed operand "(uint8)0U".

How come this operand is signed while I am explicitly casting it to uint8 which is equivalent to unsigned char and also postfixing it with literal U which stands for unsigned integer?

Upvotes: 1

Views: 288

Answers (2)

chqrlie
chqrlie

Reputation: 144951

0U has type unsigned int and (uint8)0U has type unsigned char, but like all types smaller than int, it gets promoted to int in an expression context such as an operand to ~.

You should just remove the cast and use ~0U.

Note however that on systems with 16- or 32-bit ints using two's complement representation (almost all current systems*):

  • ~0U has type unsigned int and evaluates to 0xFFFFFFFF (0xFFFF if int has 16 bits).
  • ~(uint8)0U has type int and evaluates to -1, which has the same bit representation, whereas
  • (uint8)~0U evaluates to 0xFF with type int.

Depending on the context, one might be more appropriate than the other.

The static analyser underscores the often unexpected side effect of the C integer promotion rules...


* embedded 8- and 16-bit CPUs use 16-bit ints, whereas laptop, desktop and server main CPUs use 32-bit ints. Non two's complement representations for signed integers are obsolete and will be removed from the C2x of the C Standard

Upvotes: 6

Lundin
Lundin

Reputation: 214265

See Implicit type promotion rules, the ~ operator applies the integer promotions on its operand. Or study appendix C of MISRA C:2012.

MISRA or not, casting to a small integer type such as uint8_t before applying ~ doesn't make any sense, it can even be considered a bug in your case since you convert a unsigned int to uint8_t, which in turn gets implicitly promoted to int and you end up with a signed -1 which isn't intended.

However, from a MISRA C:2012 perspective, a static analyser should only bother to check the type before implicit promotion. As per rule 10.1 the only allowed operand of ~ is one that's essentially unsigned. That is, code such as ~(uint8_t)0U is strange and bad, but as far as I can tell, MISRA C:2012 compliant.

The older deprecated MISRA C:2004 had a requirement that you should cast the result to what that version of MISRA called underlying type - the type an expression would have had if not for implicit promotion. So you'd write (uint8_t)~0U. This rule of underlying type was a bit blunt and misguided however, the current concept of essential type works better and is easier to understand. If you have an old tool checking for MISRA C:2004 compliance then the warning makes perfect sense.

Either way, the recommended practice is to always cast the result of ~ to the unsigned type intended to be used by the expression. That way you can't go wrong.

Upvotes: 0

Related Questions