STVD+Cosmic4.3.4常数取“~”问题!谢谢!
tmp = ~0x01; //编译及执行结果是正确的,
WDR();
if ( tmp == ~0x01) //编辑及执行结果是错误的,看下面汇编,为什么比较的时候不支持“~”呢?有那位可以讲解一下,谢谢!
{
WDR();
}
WDR();
main.c:44 WDR();
0x8fe0 <main+4> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
main.c:46 tmp = ~0x01;
0x8fe4 <main+8> 0xA6FE LD A,#0xfe LD A,#0xfe
0x8fe6 <main+10> 0x6B01 LD (0x01,SP),A LD (0x01,SP),A
main.c:47 WDR();
0x8fe8 <main+12> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
main.c:49 if ( tmp == ~0x01)
0x8fec <main+16> 0x7B01 LD A,(0x01,SP) LD A,(0x01,SP)
main.c:54 WDR();
0x8fee <main+18> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
tmp = ~0x01;
WDR();
if ( tmp == 0xfe) //去掉“~”这样写编译执行就正常,头晕!
{
WDR();
}
WDR();
main.c:44 WDR();
0x8fe0 <main+4> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
main.c:46 tmp = ~0x01;
0x8fe4 <main+8> 0xA6FE LD A,#0xfe LD A,#0xfe
0x8fe6 <main+10> 0x6B01 LD (0x01,SP),A LD (0x01,SP),A
main.c:47 WDR();
0x8fe8 <main+12> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
main.c:49 if ( tmp == 0xfe)
0x8fec <main+16> 0x7B01 LD A,(0x01,SP) LD A,(0x01,SP)
0x8fee <main+18> 0xA1FE CP A,#0xfe CP A,#0xfe
0x8ff0 <main+20> 0x2604 JRNE 0x8ff6 JRNE 0x8ff6
main.c:51 WDR();
0x8ff2 <main+22> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
main.c:54 WDR();
0x8ff6 <main+26> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
改成 int tmp;
~0x01结果是(int)0XFFFE,而不是0xFE。
(此处缘由庆参考C语言标准关于~运算符号的描述)
如果tmp是八位数,
if ( tmp == ~0x01) 恒不成立。
改成INT还是错:
main.c:44 WDR();
0x8fe0 <main+4> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
main.c:46 tmp = ~0x0001;
0x8fe4 <main+8> 0xAEFFFE LDW X,#0xfffe LDW X,#0xfffe
0x8fe7 <main+11> 0x1F01 LDW (0x01,SP),X LDW (0x01,SP),X
main.c:48 WDR();
0x8fe9 <main+13> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
main.c:50 if ( tmp == ~0x0001)
0x8fed <main+17> 0x1E01 LDW X,(0x01,SP) LDW X,(0x01,SP)
main.c:55 WDR();
0x8fef <main+19> 0x35AA50E0 MOV 0x50e0,#0xaa MOV _IWDG_KR,#0xaa
只要加了“~”
编译结果就只有一句话了:
main.c:50 if ( tmp == ~0x0001)
0x8fed <main+17> 0x1E01 LDW X,(0x01,SP) LDW X,(0x01,SP)
后面的比较语句就没有了:
0x8fee <main+18> 0xA1FE CP A,#0xfe CP A,#0xfe
0x8ff0 <main+20> 0x2604 JRNE 0x8ff6 JRNE 0x8ff6
少了这两句!
谢谢“voidx”!刚才查了一下,标准C确实是16位的:
4. 求反运算 求反运算符~为单目运算符,具有右结合性。 其功能是对参与运算的数的各二进位按位求反。例如~9的运算为: ~(0000000000001001)结果为:1111111111110110
不过以前用AVR的时候都是这么写的,都正常!现在16位8位都试了,结果一样,那应该跟位数没关系了!
就目前情况来看估计就是编译器的地雷了!用Cosmic是越深入心理越发虚啊!唉!就这样的效果还要2多万元!!!我买CVAVR时才花了一千多元,还没出过这么低级的错误!
编译器我都用IAR。
IAR相对来说,语言还是比较标准的。
IARSTM8才出第一版,效率比Cosmic略差。
不多相信IAR后续版本效率超Cosmic不是难事。
这个还真不能怪编译器,这本来就是程序没写好嘛:
int main(int argc,char *argv[])
{
uint8 tmp = ~1;
if(tmp == ~1){
tmp += 1;
}
}
编译器警告:src\user\main.c(111): warning: #514-D: pointless comparison of unsigned integer with a negative constant
发现comsic确实存在问题。
==比较,未按照标准C要求进行提升。
实例1:
int main()
{
int temp;
temp=~0x01;
if(temp==~0x01)
{
_asm("nop");
}
while (1);
}
结果:if(temp==~0x01)为真,这里正确。
~0x01的值是(int)0xfffe,即-2。
(int)-2==(int)-2,结果为真。
实例2:
int main()
{
unsigned int temp;
temp=~0x01;
if(temp==~0x01)
{
_asm("nop");
}
while (1);
}
结果:comsic为假,iarstm8为真。
temp为unsigned int类型,temp=~0x01后,temp的值为0xFFFE,
(unsigned int)0xFFFE==(int)(-2)应该为真,
原因是int与unsigned int比较,int要提升至unsigned int,
即:(unsigned int)0xFFFE==(unsigned int)((int)(-2))为真。
iar,avrgcc都是正确的。
实例3:
int main()
{
if((unsigned int)(-2)==(-2))
{
_asm("nop");
}
while (1);
}
结果comsic为假,iarstm8,avrgcc为真。
原因同上。
刚刚全部试了,现在已经明白了,谢谢voidx,hgjinwei!
原因如下:编译器在作比较时的对于常数取“~”当有 “ 符号 ” 的 “int” 类型所以,如果变量定义的不是
“int” 则需要用强制类型转换才能正确执行!
(相应数据类型)~0x01 这样就正确了!
比如:(unsigned char)~0x01这样子写就正确!
再次感谢各位的解答!
好垃圾的编译器。。好垃圾的寄存器分布啊。。又不得不用。。