发现STVD+Cosmic 4.3.4 unsigned char “+”运算问题!(char 也一样)给大家提个醒! 同时也希望其他同仁发现问题也给大伙提醒一下!谢谢!
volatile unsigned char tmp[3];
tmp[0]=0xdd;
tmp[1]=0xbb;
tmp[2]=0x98;
//以下运算结果是错误的
if (tmp[0]+tmp[1]==tmp[2])
{
WDR();
}
main.c:39 tmp[0]=0xdd;
0x8fa0 <main+2> 0xA6DD LD A,#0xdd LD A,#0xdd
0x8fa2 <main+4> 0x6B03 LD (0x03,SP),A LD (0x03,SP),A
main.c:40 tmp[1]=0xbb;
0x8fa4 <main+6> 0xA6BB LD A,#0xbb LD A,#0xbb
0x8fa6 <main+8> 0x6B04 LD (0x04,SP),A LD (0x04,SP),A
main.c:41 tmp[2]=0x98;
0x8fa8 <main+10> 0xA698 LD A,#0x98 LD A,#0x98
0x8faa <main+12> 0x6B05 LD (0x05,SP),A LD (0x05,SP),A
main.c:43 if (tmp[0]+tmp[1]==tmp[2])
0x8fac <main+14> 0x7B05 LD A,(0x05,SP) LD A,(0x05,SP)
0x8fae <main+16> 0x5F CLRW X CLRW X
0x8faf <main+17> 0x97 LD XL,A LD XL,A
0x8fb0 <main+18> 0x1F01 LDW (0x01,SP),X LDW (0x01,SP),X
0x8fb2 <main+20> 0x7B04 LD A,(0x04,SP) LD A,(0x04,SP)
0x8fb4 <main+22> 0x5F CLRW X CLRW X
0x8fb5 <main+23> 0x1B03 ADD A,(0x03,SP) ADD A,(0x03,SP)
0x8fb7 <main+25> 0x2401 JRNC 0x8fba JRNC 0x8fba
0x8fb9 <main+27> 0x5C INCW X INCW X
0x8fba <main+28> 0x02 RLWA X,A RLWA X,A
0x8fbb <main+29> 0x1301 CPW X,(0x01,SP) CPW X,(0x01,SP)
0x8fbd <main+31> 0x2604 JRNE 0x8fc3 JRNE 0x8fc3
main.c:45 WDR();
0x8fbf <main+33> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
volatile unsigned char tmp[3];
tmp[0]=0xdd;
tmp[1]=0xbb;
tmp[2]=0x98;
//这样子运算才是对的!不知道从标准C语言来说是不是必须要这么做?那位专家给解释一下,谢谢!另外有没有那个网站对这一方面有详细介绍的?谢谢!
if ((unsigned char)(tmp[0]+tmp[1])==tmp[2])
{
WDR();
}
main.c:39 tmp[0]=0xdd;
0x8fa0 <main+2> 0xA6DD LD A,#0xdd LD A,#0xdd
0x8fa2 <main+4> 0x6B01 LD (0x01,SP),A LD (0x01,SP),A
main.c:40 tmp[1]=0xbb;
0x8fa4 <main+6> 0xA6BB LD A,#0xbb LD A,#0xbb
0x8fa6 <main+8> 0x6B02 LD (0x02,SP),A LD (0x02,SP),A
main.c:41 tmp[2]=0x98;
0x8fa8 <main+10> 0xA698 LD A,#0x98 LD A,#0x98
0x8faa <main+12> 0x6B03 LD (0x03,SP),A LD (0x03,SP),A
main.c:43 if ((unsigned char)(tmp[0]+tmp[1])==tmp[2])
0x8fac <main+14> 0x7B02 LD A,(0x02,SP) LD A,(0x02,SP)
0x8fae <main+16> 0x1B01 ADD A,(0x01,SP) ADD A,(0x01,SP)
0x8fb0 <main+18> 0x1103 CP A,(0x03,SP) CP A,(0x03,SP)
0x8fb2 <main+20> 0x2604 JRNE 0x8fb8 JRNE 0x8fb8
main.c:45 WDR();
0x8fb4 <main+22> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
楼主自己搞错了。
//0Xdd+0xbb==0x198
//0x198==0x98 恒不成立
根据标准C规定,+,==运算数操作数不满int,自动转换int。
(这叫做integer promotions)
if (tmp[0]+tmp[1]==tmp[2])
相当于:
if ((int)((int)tmp[0]+(int)tmp[1])==(int)tmp[2])
谢谢stm8s103!有没有中文的书推荐一本看看?谢谢!
以前用CodeVisionAVR 时没问题!刚刚试了一下IAR STM8S跟RIDE7 STM8S也是一样的问题!
有问题,说明这个编译器是按照规范作的;没有问题,说明这个编译器不符合规范,编译器有问题。
一直觉得还是有点不对劲儿。
刚冲凉时突然想到:
STM8是一款8位单片机,其int应该是8bit的。
而楼主代码中,COSMIC缺省转换成16bit来运算。
这一点容易导致误解。
STM8绝对是8位机,而不是16位机,呵呵。
IAR EWARM转换成32位是可以理解的。
而且If both operands have the same type, then no further conversion is needed.
这句怎么理解?
楼主代码中,所有参与运算的变量均为unsigned char,应该不进行整数提升才对呀?这也符合我以前的想法。
这个也是ANSI C的,应该是C89里面的,其描述与7楼的不一样。
3.2.1.5 Usual arithmetic conversions
Many binary operators that expect operands of arithmetic type cause
conversions and yield result types in a similar way. The purpose is
to yield a common type, which is also the type of the result. This
pattern is called the usual arithmetic conversions: First, if either
operand has type long double, the other operand is converted to long
double . Otherwise, if either operand has type double, the other
operand is converted to double. Otherwise, if either operand has
type float, the other operand is converted to float. Otherwise, the
integral promotions are performed on both operands. Then the
following rules are applied: If either operand has type unsigned long
int, the other operand is converted to unsigned long int.
Otherwise, if one operand has type long int and the other has type
unsigned int, if a long int can represent all values of an unsigned
int, the operand of type unsigned int is converted to long int ; if a
long int cannot represent all the values of an unsigned int, both
operands are converted to unsigned long int. Otherwise, if either
operand has type long int, the other operand is converted to long int.
Otherwise, if either operand has type unsigned int, the other
operand is converted to unsigned int. Otherwise, both operands have
type int.
上面的描述与实验结果一致。
而7楼的描述理解起来,与实验结果不一致。
本人感觉目前的编译器应该都是遵循C89的
The compilers from IAR Systems adhere to a freestanding environment implementation of the ISO/IEC 9899:1990 Programming Languages C standard, changed by Amendment 1:1995, Technical corrigendum 1:1994, and Technical corrigendum 2:1996.
We supply some of the functionality of the ISO/IEC 9899:1999 Programming Languages C as well.
If both operands have the same type, then no further conversion is needed.
(这句话C89里面也有,只细看)
这句话是有前提条件的:
Otherwise, the integer promotions are performed on both operands.Then the
following rules are applied to the promoted operands:
通俗理解就是:只要操作数不是浮点数,不管三七二十一,首先把操作符两边的运算数进行整型提升(integer promotions),然后再根据提升的结果,再进行转换。
c89,c99这里其实是一个意思,只不过C99用了一些新的专有名词,并且扩展到复数范围内了,还有就是增加了一个新类型long long int。
一直觉得还是有点不对劲儿。
刚冲凉时突然想到:
STM8是一款8位单片机,其int应该是8bit的。
而楼主代码中,COSMIC缺省转换成16bit来运算。
这一点容易导致误解。
STM8绝对是8位机,而不是16位机,呵呵。
IAR EWARM ...
呵呵,为何STM8是8位MCU,其INT咎应该是8BIT的?
INT到底是多少位和MCU没关系把!?这个似乎只和C编译器有关系的!
个人原来的理解是默认值应该就是按参与运算的数据类型决定(当然如果类型不一样自然要转换,CodeVisionAVR 用多了就是知道,相同类型,比如8位与8位运算,结果是8位,但是它会提示你可能会发生溢出,这点就很好了,如果需要把结果变成另外一个类型,程序员自然会加转换,不然像这种暗箱操作会出人命的,还好产品还没正式投产),昨天又查了一天,把所有有运算符的都结加上强制类型转换上去了,不管到底需不需要!唉,不然心里没底啊!
看来楼上深受CodeVisionAVR毒害。(把不标准当作了标准)
用GCC,IAR,不会有这等问题。