搜索
bottom↓
回复: 27

if (0!=(~0xFF)) 条件应该不成立的怎么还会执行的

[复制链接]

出0入0汤圆

发表于 2011-4-15 20:59:15 | 显示全部楼层 |阅读模式
#include<REGX52.H>

unsigned char i,j,k;

void main(void)
{

        j=0;
        k=~0xFF;

        if (0!=(~0xFF)) //左边是0 右边也是0 应该是相等的 条件不成立不执行i++的
        {
                i++;//但还是执行这了
        }

        if (j!=k) //都是0,条件不成立
        {
                i++; //这次就不执行的
        }

        while (1);


}

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2011-4-15 21:04:22 | 显示全部楼层
数据类型
if(0!=(~(unsigned char )0xff))

出0入0汤圆

发表于 2011-4-15 21:08:10 | 显示全部楼层
查书,C标准,典型问题:整型类型提升。

0 != (~0xFF) 的完整描述: (int的0) != ~(int的0xFF)。0和0xFF都是int型。假定int = 16bit;于是 int 0 != int 0xFF00 => True。

语句k = ~0xFF,有: k = (unsigned char)(~ (int 0xFF)) => k = (uchar)(int 0xFF00) => k = 0.
j != k 标准C为:(int)j != (int)k 所以相等。

出0入0汤圆

 楼主| 发表于 2011-4-15 21:09:40 | 显示全部楼层
试了下还是执行的啊

出0入0汤圆

发表于 2011-4-15 21:10:31 | 显示全部楼层
回复【1楼】sharpufo  风生水起月皎白
数据类型
if(0!=(~(unsigned char )0xff))
-----------------------------------------------------------------------

还是错的。。。。

if(0 != (unsigned char)( ~0xFF))

出0入0汤圆

发表于 2011-4-15 21:16:09 | 显示全部楼层
sorry,我也是随手一写,想到是类型的问题,不过忘了次序的问题。
应该是楼上这样,把(~0xff)类型转化为unsigned char 类再来与0比较.
int 0与unsigned char 0 比较是相等的,会把后者也转化为 int 0.

出0入0汤圆

发表于 2011-4-15 21:23:23 | 显示全部楼层
直接查看汇编代码分析分析不就行了。

出0入0汤圆

 楼主| 发表于 2011-4-15 21:30:12 | 显示全部楼层
回复【2楼】dr2001
-----------------------------------------------------------------------

讲的很详细啊....谢了...上次貌似问过一次了也是类型的问题....这次又忘了,汗
不过我没一本C语言的书....查也没的查...

出0入0汤圆

 楼主| 发表于 2011-4-15 21:30:50 | 显示全部楼层
回复【6楼】eefans
-----------------------------------------------------------------------

分析了..但搞不懂为什么编译成那样了

出0入0汤圆

发表于 2011-4-15 21:33:39 | 显示全部楼层
涨知识了

出0入0汤圆

发表于 2011-4-15 21:34:29 | 显示全部楼层
另外,如果编译器开启了优化
if (0!=(~0xFF)) //左边是0 右边也是0 应该是相等的 条件不成立不执行i++的
{
i++;//但还是执行这了
}

会被直接优化成

i++;

出0入0汤圆

发表于 2011-4-15 23:28:53 | 显示全部楼层
51 处理器 怎么会默认是整形?

出0入0汤圆

发表于 2011-4-15 23:42:56 | 显示全部楼层
翻出 keil 来编译了一下
int main()
{
        unsigned char k,f,g,h;
        k=~0XFF;
        f=0X00;
        g=0;
        h=0;

        if(0!=k)
        {
        k++;
        }
        if(0!=f)
        {
        f++;
        }
        if(0!=g)
        {
        g++;
        }

        if(0!=~0XFF)
        {
        h++;
        }
}

以上代码 统统符合逻辑

编译后的代码  自行参阅

C:0x0000    020010   LJMP     C:0010
     3: int main()
     4: {
     5:         unsigned char k,f,g,h;
     6:         k=~0XFF;
C:0x0003    E4       CLR      A
C:0x0004    FF       MOV      R7,A
     7:         f=0X00;
C:0x0005    FE       MOV      R6,A
     8:         g=0;
C:0x0006    FD       MOV      R5,A
     9:         h=0;
    10:  
    11:         if(0!=k)
C:0x0007    6001     JZ       C:000A
    12:         {
    13:         k++;
C:0x0009    0F       INC      R7
    14:         }
    15:         if(0!=f)
C:0x000A    EE       MOV      A,R6
C:0x000B    6001     JZ       C:000E
    16:         {
    17:         f++;
C:0x000D    0E       INC      R6
    18:         }
    19:         if(0!=g)
C:0x000E    ED       MOV      A,R5
    20:         {
C:0x000F    22       RET      
C:0x0010    787F     MOV      R0,#0x7F
C:0x0012    E4       CLR      A
C:0x0013    F6       MOV      @R0,A
C:0x0014    D8FD     DJNZ     R0,C:0013
C:0x0016    758107   MOV      0x81,#0x07
C:0x0019    020003   LJMP     main(C:0003)

出0入0汤圆

发表于 2011-4-16 07:58:40 | 显示全部楼层
记住(标准C规则):
1.char,usnigned char,signed char本质上没有逻辑,算术运算,char,usnigned char,signed char本质上并不能直接参与运算。
2.所有的算术与逻辑操作符,都要求操作数至少是int。
3.char,usnigned char,signed char参与运算,实际上是把char,usnigned char,signed char先转换成int,或者unsigned int,再再与运算。(C标准里面,这个规则叫整型提升)。
4.C语言所有字面值整型常量,都有自己的类型,而且至少为int。

实际上,绝大大部分编译器,都是遵守上边的规则的。

举例:
1.if (0!=(~0xFF))
0,0xff,不要错误地认为0,0xff的类型是unsigned char,或者没有类型。
实际上所有字面值整型常量,都有自己的类型,这里为int。

2.if (0!=(~(unsigned char)0xFF))
不要错误地认为~unsigned char结果还是unsigned char。
实际上,unsigned char并不能直接进行~运算,需要先提升至int才能运算。
而且~运算符也要有操作数必须至少是int。
这个unsigned char转换没用,因为char参与运算,总是会被提升,至少为int。

3.long a=10*10000;   (假定int是16位)
不要错误地认为,a的结果是100000,实际上结果为-31072
原因C语言所有字面值整型常量,都有自己的类型,而且至少为int,这里10和10000都是int型,
而int与int相乘,结果还是int,如果有益出,溢出会被丢弃。10*10000结果为-31072。

出0入0汤圆

发表于 2011-4-16 09:02:26 | 显示全部楼层
回复【13楼】CC2530 上官金虹

记住(标准c规则):
1.char,usnigned char,signed char本质上没有逻辑,算术运算,char,usnigned char,signed char本质上并不能直接参与运算。
2.所有的算术与逻辑操作符,都要求操作数至少是int。
3.char,usnigned char,signed char参与运算,实际上是把char,usnigned char,signed char先转换成int,或者unsigned int,再再与运算。(c标准里面,这个规则叫整型提升)。
4.c语言所有字面值整型常量,都有自己的类型,而且至少为int。
实际上,绝大大部分编译器,都是遵守上边的规则的。
举例:
1.if (0!=(~0xff))
0,0xff,不要错误地认为0,0xff的类型是unsigned char,或者没有类型。
实际上所有字面值整型常量,都有自......
-----------------------------------------------------------------------

这是 Keil C

出0入0汤圆

发表于 2011-4-16 09:19:59 | 显示全部楼层
Keil C也是遵守这个规则,

ls的把 unsigned char k,f,g,h ; 放到main函数外面再试试

出0入0汤圆

发表于 2011-4-16 09:21:15 | 显示全部楼层
或者把优化等级设置成0也能看到效果

出0入0汤圆

发表于 2011-4-16 10:03:04 | 显示全部楼层
因为变类型是unsigned char中间运算结果即使是int,也会转换成unsigned char.

比如:
unsigned char k,f;
f=0xff;
k=~f;

虽然~f的结果并不为0,但是在把~f赋值给k的时候,已经自动转成unsigned char,
相当于k=(unsigned char)(~0xff);
所有得到结果k为0,但这并不表示~0xff结果为0.

出0入0汤圆

发表于 2011-4-16 10:17:47 | 显示全部楼层
回复【16楼】Jason022
或者把优化等级设置成0也能看到效果
-----------------------------------------------------------------------

按你的方法试了一下,是这样,想了想觉得应该是32bit交叉编译时编译器的处理问题,因为试过0XFFFFFF,0XFFFFFFFF,凡是奇数字节都被认为是真,另如果在8位系统编译,我就不信还是真

出0入0汤圆

发表于 2011-4-16 10:29:09 | 显示全部楼层
mark

出0入0汤圆

 楼主| 发表于 2011-4-16 10:42:15 | 显示全部楼层
#include<REGX52.H>

unsigned int R; //R是整型
unsigned char i,j,k;




void main(void)
{
        j=0;
        k=0xFF; //K=FF

        R = ~0xFF; //这时R的结果是FF00 整型提升了
        R = ~j;    //j为0 R结果为FFFF
        R = ~k;    //k为FF, R结果为FF00 说明char被整型提升了
        R=0;

        if (0!=~k)   //~k的结果应该为FF00 就是左右的结果不一样 条件应该是成立的
        {
                i++; //但没有执行这 说明~k的结果为0 两边相等的才条件不成立 说明没有被整型提升
        }

       
        if (R!=~k) //R为0  右边~k为FF00
        {
                i++;//这次执行了 ,说明右边~k应该就是等于FF00了  
        }

//什么时候会被整型提升看来还与另一个比较的数有关
//if (R!=~k)  R为int 右边比较时右边就整型提升成了FF00
       
//但if (0!=~k) 左边的0也应该认为是整型(楼上的帖子说明了) 右边也应该整型提升才对 实际没有整型提升
//晕了...

        while (1);




}

出0入0汤圆

发表于 2011-4-16 10:44:53 | 显示全部楼层
楼上的几位都讲的很详细,学习了,多谢

出0入0汤圆

发表于 2011-4-16 10:59:32 | 显示全部楼层
Keil C51的话,可以使用NOINTPROMOTE关闭整型提升,提升一些性能。
参见:
http://www.keil.com/support/man/docs/c51/c51_intpromote.htm
http://www.keil.com/support/man/docs/c51/c51_nointpromote.htm
http://www.keil.com/support/docs/1754.htm

如果专注于Keil C51平台,这样做没有问题,若还要关注其它的平台,这样做就要斟酌了,搞混的可能性较大(这是C语言中的一个大地雷)。
不过一个好习惯就是完全不要依赖编译器整型提升: 每次使用字面量时都强制指定其类型。

出0入0汤圆

 楼主| 发表于 2011-4-16 11:34:31 | 显示全部楼层
#include<REGX52.H>

unsigned int R; //R是整型
unsigned char i,j,k;




void main(void)
{
        j=0;
        k=0xFF; //K=FF



        if (j!=~0xFF) //右边被整型成FF00
        {
                i++; //所以执行,
        }//~0xFF 证明提升的


        if (k!=~0) //那现在右边应该是FFFF 左边K为FF
        {
                i++;//(没执行)也不等那应该要执行的,现在却没执行 ....那只能说是有时候整型提升 有时候不提升
        }// ~0 没提升 就是FF

    k=0xFE;
        if (k!=~1) //那现在右边应该是FFFE
        {
                i++;//(没执行)
        }//~1 没提升 就是FE

       
    k=0x01;
        if (k!=~0xFE) //那现在右边应该是FF01
        {
                i++;//执行的
        }//~0xFE 提升的
       
       
//就算一样的写法,只是右边的数值大小不一样时,居然有的提升有的不提升,,实在是晕了
       

        while (1);




}

出0入0汤圆

发表于 2011-4-16 11:45:55 | 显示全部楼层
回复【23楼】jsjjccc

#include<regx52.h>
unsigned int r; //r是整型
unsigned char i,j,k;

void main(void)
{
j=0;
k=0xff; //k=ff
if (j!=~0xff) //右边被整型成ff00
{
i++; //所以执行,
}//~0xff 证明提升的
if (k!=~0) //那现在右边应该是ffff 左边k为ff
{
i++;//(没执行)也不等那应该要执行的,现在却没执行 ....那只能说是有时候整型提升 有时候不提升
}// ~0 没提升 就是ff
    k=0xfe;
if (k!=~1) //那现在右边应该是fffe
{
i++;//(没执行)
}//~1 没提升 就是fe
    k=0x01;
if (k!=~0xfe) //那现在右边应该是ff01
......
-----------------------------------------------------------------------

KEIL C没有遵守标准C。

楼主换其他编译器试验。
比如,IAR,GCC,或者KEIL MDK FOR ARM(不是KEIL C51).
或者用VC,C++Builder试验。

只不过注意32位机int是32位。

出0入0汤圆

发表于 2011-4-16 13:45:38 | 显示全部楼层
经简单测试,对常数[0,0xFF],有[0,0x7F]不进行整型类型提升;[0x80,0xFF]进行整型类型提升。

这样的话,应该是Keil的一个Bug;或者Keil没有按照标准C实现。

出0入0汤圆

发表于 2012-4-4 17:08:42 | 显示全部楼层
好贴,有学到了点东西!

出0入0汤圆

发表于 2012-4-4 18:47:24 | 显示全部楼层
右边也是0


you need to read about type promotion in a good C book.
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-20 04:25

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表