You did not define BYTE
; I'll assume it is identical to stdint.h
s uint8_t
(which should always be preferred to homebrew types).
a |= b
(roughly) translates to a = a | b
, including integer promotions here as part of the usual arithmetic conversions. For the types given this means a
is converted to int
before the operation is performed, yielding an int
result. The final assignment will truncate this int
for the assignment, possibly loosing information (likely the sign), because int
is at least 16 bits wide.
Casting b
does not help, because the conversion is done for the operation and you have to cast the result.
The transformation is also the solution:
uint8_t a;
a = (uint8_t)(a | b);
Explicitly tells the compiler you know what you do and to shut up. Just make sure you really know what you do!
This is not very elegant, but the only way to suppress the warning. OTOH the behaviour is arithmetically consistent with the simple assignment-version.
Edit: You should use unsigned integer constants when shifting where possible. Even more, as you operate on unsigned variables anyway. As a general rule, try to avoid mixing signed and unsigned operands. If that is not possible make sure you know what is going on and catch all invalid cases.
Edit2: For some implementations/signed integer representations and some combinations for types and operations, it is possible to prove no information can be lost, thus the warning is obsolete. However, it seems this would require knowledege of machine details which might not be available at the stage the warning is generated.
Maybe the C standard should have defined the compound assignment to implicitly include the final cast. That would not be the only legacy. OTOH, this behaviour might have generated confusion in the other direction to people which were not aware of this (note that in C an assignment yields a result!). Which is the lesser of two evils?