A small test app for 8051, SDCC v2.9.0:
volatile unsigned char a = 0xf0;
volatile unsigned char b = 0x0f;
if (a == ~b)
Is compiled to:
; D:\bug\main.c:6: if (a == ~b)
; D:\bug\main.c:8: return 0xaa;
; D:\bug\main.c:10: return 0xbb;
The comparison fails and 0xAA is returned, because
both sides of the comparison are extended to 16 bits
(int). And 0x00f0 is obviously not equal to 0xfff0.
I assume this is due to the complement operator.
Is this correct behavior? I did not expect an implicit
Yes, this is correct. ISO/IEC 9899:1999 section 126.96.36.199 "Unary arithmetic operators" paragraph 4 states: "The result of the ~ operator is the bitwise complement of its (promoted) operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set). The integer promotions are performed on the operand, and the result has the promoted type. If the promoted type is an unsigned type, the expression ~E is equivalent to the maximum value representable in that type minus E." Parenthetical expressions are part of the original.
Informally, the standard generally says that C operators promote integer types to at least an int before applying the operator, which in turn will cause the operator result to be at least an int. If you need the result to be a smaller type, you will need to add an explicit cast or assignment:
if (a == (unsigned char)~b)
b = ~b;
if (a == b)
(although, of course, this second example has the side effect of changing b)
Thank you for your quit response. I went for the explicit-cast solution. I wasn't aware that complement does lead to a type promotion, too. Now I'll be more careful.
That should read "quick response"… typo…
Log in to post a comment.