We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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