I think there is a bug in the C51 and CX51 compilers regarding integer promotion. I have not deselected integer promotion and thus expect proper C semantics without adding casts. The bug seems to be appearing in different cases but working in others, like with the "?" operator versus the if-statement.
Se code below with comments on actual and expected results.
typedef unsigned char uint8_t; typedef signed char int8_t; typedef signed int int16_t; volatile int x; void foo(void) { int8_t b1 = -128, b2 = 0; x = -b1; // OK: x = 128 x = b1 > 0 ? 0 : -b1; // ERR: x = -128 if (b1 > 0) x = 0; else x = -b1; // OK: x = +128 x = -(b1-b2); // OK: x = 128 x = (b1-b2) > 0 ? 0 : -(b1-b2); //ERR: x = -128 if ((b1-b2) > 0) x = 0; else x = -(b1-b2); // OK: x = +128 } void fie(void) { uint8_t b1 = 10, b2 = 20; x = (b1-b2) > 0 ? 0 : // ERR: This branch is executed -> x = 0 -(b1-b2); if ((b1-b2) > 0) x = 0; // ERR: This branch is executed -> x = 0 else x = -(b1-b2); } #define ABS(a) ((a) > 0 ? (a) : (-(a))) #define ABS_FIX(a) ((int16_t)(a) > 0 ? (a) : ((int16_t)-(a))) void fum(void) { int8_t b1 = -128; uint8_t b2 = 10, b3 = 20; x = ABS(b1); // ERR: x = -128 x = ABS_FIX(b1); // OK: x = +128 x = ABS(b2-b3); // ERR: x = 246 x = ABS_FIX(b2-b3); // OK: x = 10 } int main(void) { foo(); fie(); fum(); return 0; }
You've omitted some detail.
Like:
The version of the compiler you're using.
What optimizations, and whether the results change when you change optimizations.
Here is the missing info;
The problem is the same in optimize level 0 and 8.
Tool Version Numbers: Toolchain: PK51 Prof. Developers Kit Version: 8.18 Toolchain Path: C:\Keil\C51\BIN\ C Compiler: C51.Exe V8.18 Assembler: A51.Exe V8.01 Linker/Locator: BL51.Exe V6.20 Librarian: LIB51.Exe V4.24 Hex Converter: OH51.Exe V2.6 CPU DLL: S8051.DLL V3.65 Dialog DLL: DP51.DLL V2.54
Always put parentheses around what you are evaluating, it's surprising what the results will be if you don't. And no it's not a bug in the compiler just your code.
Stephen
Why isn't this a bug? Is C51 a special kind of compiler that is supposed to produce different results than any other C-compiler?
Put parentheses around the evaluation like you would (and did) in if then else statements and it will work. That's not a bug it's a matter of operator precedence and evaluation of the expression.
Essentially your expressions when using the ? operator are ALWAYS evaluating to zero for the '?' operator and that means the expression past the ':' is always the result.
This is a common mistake and Lint would have picked it up immediately.
Sorry but you are wrong. This is not a operator precedence bug, maybe in C51, so I tested adding parentheses around all expressions. The result is exactly the same.
The code with extra parentheses follows.
typedef unsigned char uint8_t; typedef signed char int8_t; typedef signed int int16_t; volatile int x; void foo(void) { int8_t b1 = -128, b2 = 0; x = -b1; // OK: x = 128 x = ((b1) > 0) ? (0) : (-b1); // ERR: x = -128 if (((b1) > 0)) x = 0; else x = -b1; // OK: x = +128 x = -(b1-b2); // OK: x = 128 x = ((b1)-(b2)) > 0 ? 0 : (-(b1-b2)); //ERR: x = -128 if (((b1)-(b2)) > 0) x = 0; else x = -(b1-b2); // OK: x = +128 } void fie(void) { uint8_t b1 = 10, b2 = 20; x = ((b1)-(b2)) > 0 ? 0 : // ERR: This branch is executed -> x = 0 (-((b1)-(b2))); if (((b1)-(b2)) > 0) x = 0; // ERR: This branch is executed -> x = 0 else x = -(b1-b2); } #define ABS(a) (((a) > 0) ? (a) : (-(a))) #define ABS_FIX(a) (((int16_t)(a) > 0) ? (a) : ((int16_t)-(a))) void fum(void) { int8_t b1 = -128; uint8_t b2 = 10, b3 = 20; x = ABS(b1); // ERR: x = -128 x = ABS_FIX(b1); // OK: x = +128 x = ABS((b2-b3)); // ERR: x = 246 x = ABS_FIX((b2-b3)); // OK: x = 10 } int main(void) { foo(); fie(); fum(); return 0; }
I don't agree that this is a problem with precedence.
This is the part I concentrated on:
x = b1 > 0 ? 0 : -b1; // ERR: x = -128
I ran it through the Keil ARM compiler and got the answer you (and I) expected.
I would take it up with Keil support.
Looks like I am wrong indeed. The parser appears to be evaluating the second value in the comparison operator expression and using that as the resultant of the expression. This of course means it's a constant false and anything post the : token is considered the resultant. If it's optimizing hmmm this could be a bug in the optimizer, have you tried the same code with no optimization? Of course that won't help you with your problem any. (sigh)
Sorry hopefully keil support will be a lot more helpful than I.
Sorry hopefully keil support will be a lot more helpful than I. they won't unless you tell them. Keil support do not (regulrily) watch the forum
Erik