最新的KEIL C51是V9.59。
在v9.59的 Release Notes 中有一个修正!主要是避免8位有符号数与无符号数比较出错的问题(在少数情况下会发生)
Corrected: in rare cases a signed compare with unsigned char treated the unsigned char as signed. This happens if the unsigned char value results from a calculated assignment. Example:
char i;
unsigned char uc0 = 254;
char c1 = 0;
void main() {
if (c1 <= (uc0 += c1)) // uc0 is wrongly treated signed => -2 therefore the condition (0 <= -2) is false
i = 1;
else
i = 0;
}
对应的汇编语言分析:
Wrong code was generated:
0000 E500 R MOV A,uc0
0002 2500 R ADD A,c1
0004 F500 R MOV uc0,A
0006 D3 SETB C
0007 6480 XRL A,#080H \
0009 F8 MOV R0,A |
000A E500 R MOV A,c1 |
000C 6480 XRL A,#080H |
000E 98 SUBB A,R0 |
000F 5004 JNC ?C0001 -> signed char compare
0011 750001 R MOV i,#01H
0014 22 RET
0015 ?C0001:
0015 E4 CLR A
0016 F500 R MOV i,A
0018 ?C0003:
0018 22 RET
The correct code is much longer because according to the C standard a cast to int is necessary:
0000 E500 R MOV A,uc0
0002 2500 R ADD A,c1
0004 FF MOV R7,A
0005 F500 R MOV uc0,A
0007 AD00 R MOV R5,c1 \
0009 ED MOV A,R5 |
000A 33 RLC A |
000B 95E0 SUBB A,ACC |
000D FC MOV R4,A -> cast of signed char to int
000E D3 SETB C \
000F ED MOV A,R5 |
0010 9F SUBB A,R7 |
0011 7480 MOV A,#080H +> implicit cast of unsigned char to int
0013 F8 MOV R0,A |
0014 6C XRL A,R4 |
0015 98 SUBB A,R0 |
0016 5004 JNC ?C0001 -> signed int compare
0018 750001 R MOV i,#01H
001B 22 RET
001C ?C0001:
001C E4 CLR A
001D F500 R MOV i,A
001F ?C0003:
001F 22 RET
To generate smaller code the signedness of the values to be compared should be the same:
...
if ((unsigned char)c1 <= (uc0 += c1))
...
0000 E500 R MOV A,uc0
0002 2500 R ADD A,c1
0004 FF MOV R7,A
0005 F500 R MOV uc0,A
0007 E500 R MOV A,c1
0009 D3 SETB C \
000A 9F SUBB A,R7 |
000B 5004 JNC ?C0001 -> unsigned char compare
000D 750001 R MOV i,#01H
0010 22 RET
0011 ?C0001:
0011 E4 CLR A
0012 F500 R MOV i,A
0014 ?C0003:
0014 22 RET