Is it implementation-defined or undefined behaviour to do things like -1 ^ mask
and other bitwise operations like signed.bitOp(unsigned)
and signed.bitOp(signed)
in C 17?
CodePudding user response:
Before the various bitwise operations in C 17, the two operands undergo the "usual arithmetic conversions" to make them have the same type. Depending on how the two types differ, you can get a signed or unsigned type. Those conversions dictate whether you have well-defined behavior or not.
If the "usual arithmetic conversions" causes a negative number to be converted to an unsigned type, then you trigger [conv.integral]/2, which causes negative numbers to be mapped to "the least unsigned integer congruent to the source integer".
The actual operation is... bitwise. The standard requires that implementations provide some binary representation of signed integers. So a bitwise operation on two signed integers is whatever you get by doing a bitwise operation on that binary representation. Since the actual representation is implementation-defined, the result is allowed to vary based on that representation. However, since the implementation requires that the signed representation's positive values match the corresponding unsigned integer's representation for the same range of numbers, bitwise operations have reliable results for positive values stored in signed integers.
The results are not undefined; you will get a value from them. But the results can be different on different implementations.
C 20 standardized 2's complement signed integer representations (since pretty much every C compiler already did this), so the results are consistent across implementations.