Reputation: 11
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
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
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