打印

难道我发现了Keil的BUG?请各位高手看一看——有图有真相

[复制链接]
楼主: XIANSir
手机看帖
扫描二维码
随时随地手机跟帖
61
447671877| | 2011-3-1 13:42 | 只看该作者 回帖奖励 |倒序浏览
菜鸟,来报个到

使用特权

评论回复
62
tyj_3| | 2011-3-1 13:50 | 只看该作者
讨论了这么多,其实看一下反汇编不就知道了.

使用特权

评论回复
63
XIANSir|  楼主 | 2011-3-1 13:55 | 只看该作者
本帖最后由 XIANSir 于 2011-3-5 14:53 编辑

57# zjaoing123
57# zjaoing123
首先,非常感谢ayb_ice老师和123jj对我的热心指导。我必须承认:对位域进行按位运算是错误的做法,以后对于位域我将只进行逻辑运算(&& || 和 !),绝不再使用按位运算符号:& | 和~。
我以后将谨记这个规则。再次感谢ayb_ice老师和123jj的教诲。

另外,关于你说的两个问题,我做一下说明:

1、对于! 和 ~的应用场合,我倒是还是知道的,但是我的想法是:对于只有一位的变量,按位取反不就是逻辑取反吗。当然,现在想想,这种想法是完全错误的,我以后再也不这样做了。

2、前辈给的pin.t_4 = ((pin.t_1=~(bit)pin.b_1) && (pin.t_2=~(bit)pin.b_2));确实是对的,但是,我之所以提出pin.t_4 = ((pin.t_1=~pin.b_1) && (pin.t_2=~pin.b_2));这个式子,
是因为,我觉得这个句子和前面的
pin.t_1 = (~pin.b_1);
pin.t_2 = (~pin.b_2);
pin.t_3 = (pin.t_1 && pin.t_2);

这三条语句是等价的,但是经过验证发现,并不是这样。
其实上面的那个问题就变成了pin.t_4 = ((pin.t_1=~pin.b_1) && (pin.t_2=~pin.b_2));这条语句中参与&&运算的到底是pin.t_1的值,还是~pin.b_1的值,这二者会导致不同结果。
根据前辈给的语句结合我的语句分析,发现参与&&运算的应该是表达式~(bit)pin.b_2的值,而不是pin.t_2的值。

总结一下:
对于位变量(包括bit变量和位域变量),可以安全使用赋值操作和逻辑操作(&& || !),但使用按位操作(~ & |)则有得到错误结果的危险。所以,对于位变量(包括bit变量和位域变量)
应该一直使用(&& || !)而避免使用(~ & |)。
如果记不住的话,那么把位变量(包括bit变量和位域变量)当记作bool类型,那么很自然的对于bool类型(位变量)就只能应用逻辑运算符,而对bool类型(位变量(包括bit变量和位域变量))
使用只适用于整型的位操作(~ & | >> <<)和算数操作(加减乘除)肯定是错误的。

再次重申,位变量(包括bit变量和位域变量)是C语言中的bool类型而不是整型,只能对其使用逻辑运算符。

好了,我的问题已经解决了,也该结贴了。谢谢大家的指点和帮助。


上面的总结完全错误,不应该把位域和bit二者搅在一起,具体解释见楼主贴

使用特权

评论回复
64
123jj| | 2011-3-1 14:17 | 只看该作者
LZ总结的很好!很有文采,赞一个!

使用特权

评论回复
65
XIANSir|  楼主 | 2011-3-1 14:39 | 只看该作者
64# 123jj
:loveliness:呵呵,多谢大侠夸赞。
不过,看来我的C学的还是不够啊,需要继续努力,向”C“进发--------》

使用特权

评论回复
66
123jj| | 2011-3-1 15:18 | 只看该作者
说实话,俺一点也不谦虚,LZ的C比俺熟练的多啦,非常羡慕ing~~~

假如不给俺手头放一本《C语言大全》,连LZ的这么短小的C语言俺都写不出,因为最基本的C关键词俺都默写不出,俺实在没时间学习,因此非常羡慕你们这些有时间学习、肯花时间学习的小辈们~~~

希LZ努力,功力早上一层楼,为国为民为自己的小家和二姨的大家,更为自已,努力用功。

使用特权

评论回复
67
dtmcp| | 2011-3-1 15:40 | 只看该作者
我的教训得出的办法:
pin.t_1 = (~pin.b_1)&&0x01;
pin.t_2 = (~pin.b_2))&&0x01;
pin.t_3 = (pin.t_1 && pin.t_2))&&0x01;

使用特权

评论回复
68
刘前辈| | 2011-3-1 17:26 | 只看该作者

大忽悠:

本帖最后由 刘前辈 于 2011-3-1 18:19 编辑

大忽悠:

为什么不一样呢,
因为(pin.t_1 && pin.t_2)是对两个位变量进行进行逻辑与
而pin.t_4 = ((~pin.b_1) && (~pin.b_2));其实是在对两个整数进行逻辑与——记得类型提升吗??


先弄清什么叫类型转换或者整型提升再说吧。

提醒一句:C语言中的类型转换/整提升是为了不同类型的操作数符号问题而产生的对策。——逻辑运算&&符两边的逻辑分量操作数有符号问题吗?都要求是bool 类型,非0即1,逻辑变量0和1再怎么转换和提升还是0和1。既然是逻辑与(bool 变量不是1就是0,)还要什么类型提升?
        结果值才可以是int(为了判断,它没有逻辑值判断指令)。

在没有找到依据之前,(教材、手册上没有讲过的东西)别自己创造概念。

使用特权

评论回复
69
123jj| | 2011-3-1 17:46 | 只看该作者
很多时候,能看出别人说错说的不完善,但俺却表达不出,没办法,不是搞这行的吃这碗饭的~~~  :L

欢迎刘大师给俺们菜鸟上上课,补习点基础知识~~~

使用特权

评论回复
70
刘前辈| | 2011-3-1 18:05 | 只看该作者
本帖最后由 刘前辈 于 2011-3-1 18:20 编辑

画蛇添足:
pin.t_4 = ((~(bit)pin.b_1) && (~(bit)pin.b_2));

什么地方推荐这种写法?
一个逻辑运算符&&两边的运算分量一定是bool 逻辑量!所以:
(~pin.b_1)只可能为逻辑值0或者1,根本不可能为其它值。举例:

uchar  aa=0x46;
uchar  bb=0x32;
uchar  cc=0;
则:  aa && bb =1;
     (~aa)&&(~cc) =1;
      (aa==1)&&(bb==1)=0;
pin.t_4 = (!pin.b_1 && !pin.b_2);    //  逻辑运算请用逻辑运算符。


/

使用特权

评论回复
71
XIANSir|  楼主 | 2011-3-1 18:27 | 只看该作者
68# 刘前辈
提醒一句:C语言中的类型转换/整提升是为了不同类型的操作数符号问题而产生的对策”

可以断定:刘前辈没有仔细看帖

你应该知道,C语言是针对没有“位处理器”的CPU制定规范的,因为很多处理器确实没有位处理器,他们的位操作只能通过对字节和整型的按位操作来完成。

在形式上,位域虽然是位变量,但是编译器对它们处理时必须提升为int或char型然后处理。

所以,对位域的位变量处理,全部都得进行类型提升,然后再处理。

明白了这些,前辈就应该明白~pin.b_1绝对不会是只取0和1,甚至他永远都不可能取0和1,只能取0xFF和0xFE.
原因是这样子的:pin.b_1在进行按位取反之前会被提升为一个字节变量,字节变量取值为0x00或0x01,然后对这个字节进行按位取反,得到的值只能是0xFE和0xFF

使用特权

评论回复
72
123jj| | 2011-3-1 18:31 | 只看该作者
画蛇添足:
pin.t_4 = ((~(bit)pin.b_1) && (~(bit)pin.b_2));

什么地方推荐这种写法?
一个逻辑运算符&&两边的运算分量一定是逻辑量!所以:
(~pin.b_1)只可能为逻辑值0或者1,根本不可能为其它值。举例:

uch ...
刘前辈 发表于 2011-3-1 18:05



刘大师说的正是,pin.t_4 = ((~(bit)pin.b_1) && (~(bit)pin.b_2));
这种写法举世没有,但客户是上帝,LZ硬要这样用pin.t_4 = ((~pin.b_1) && (~pin.b_2));
俺只能顺着LZ的思路,加个(bit),强制转换一下,以求得正确结果。

实际上在生活中,在工作上,很多时候,人在江湖,身不由己。
比如,你新到一家公司搞技术,前面的产品一看就浑身是病,改一种方案性能又好又省银子,但你不能改啊。
比如这个产品是总工设计的,你想更改,饭碗砸了,或许你要说,这家公司不做也罢!
那再假设,这个产品是其他公司设计的,公司只为其提供配套业务,你想更改,公司饭碗都被砸了,你能更改吗?
唯一的方法就是适应他,管他对错,你只能打个补丁,让他能用能正常工作即可。

使用特权

评论回复
73
XIANSir|  楼主 | 2011-3-1 18:34 | 只看该作者
70# 刘前辈
pin.t_4 = ((~(bit)pin.b_1) && (~(bit)pin.b_2));
这种写法虽然不是很好看,但是结果确实对的,为什么它是对的呢:因为bit类型是KEIL对51进行的C语言扩展语法,既然专为51扩展,那他肯定会好好利用8051的位处理器的,这样,(~pin.b_1)就会因为类型提升而导致错误的结果,而(~(bit)pin.b_1)却不会产生类型提升,而是使用51的专用位处理器进行处理,所以得到的结果是对的。

使用特权

评论回复
74
XIANSir|  楼主 | 2011-3-1 18:39 | 只看该作者
72# 123jj
“这种写法举世没有,但客户是上帝,LZ硬要这样用pin.t_4 = ((~pin.b_1) && (~pin.b_2));”


呵呵,看来俺让大侠为难了,真是不好意思啊:loveliness:,


俺这次一定记住,以后再也不对位变量使用按位操作符了,只使用赋值、逻辑运算符和==、!=运算符。
所以,前辈的辛苦还是非常有意义滴

使用特权

评论回复
75
刘前辈| | 2011-3-1 19:34 | 只看该作者
本帖最后由 刘前辈 于 2011-3-1 20:14 编辑
在形式上,位域虽然是位变量,但是编译器对它们处理时必须提升为int或char型然后处理。
所以,对位域的位变量处理,全部都得进行类型提升,然后再处理。


唉!开玩笑呢,位域 pin.b_1,……不是位变量! 是你自己定义的uchar 变量!所以运算中采用的字节变量运算代码是编译器听你的话才编译出来的。 uchar  pin.b_1 本来就是按字节运算的,和整提升根本无关!——整提升至少要提升为int 类型,51单片机2字节运算才对,根本没有提升到字节类型的,C51整提升也没有uchar 类型运算,都是2字节int 运算。——以前帖子上证实过的。所以,代码中的字节运算根本不是什么整提升出来的。逻辑运算需要操作数整提升?你从哪看来的?自己别创新!还那么肯定地,最好先看看《C语言详解》有关内容,百度上搜索一下也行。

逻辑运算符&&两边的操作数 只能是bool 变量。——这没什么疑问的,无论你是0xFF还是0xFE还是0xCD。
(0xFE)&&(0xCD) = 1;  // 正确
!(0xFE)&&(0xCD) = 0;// 正确。(0xFE)= TRUE,!(0xFE)= FALSE。


pin.b_4= (( pin.b_1== 0 ) && ( pin.b_2 == 0 )) ;       //  写法莫名其妙; 因为pin.b_4的值既可能为0,也可能为1;这取决于以前 pin.b_1 /  pin.b_2 的初始值。

到底是谁的BUG ?




使用特权

评论回复
76
123jj| | 2011-3-1 19:54 | 只看该作者
72# 123jj
“这种写法举世没有,但客户是上帝,LZ硬要这样用pin.t_4 = ((~pin.b_1) && (~pin.b_2));”

呵呵,看来俺让大侠为难了,真是不好意思啊:loveliness:,

俺这次一定记住,以后再也不对位变量使用按位 ...
XIANSir 发表于 2011-3-1 18:39



呵呵!没关系,这是俺的职业习惯,现在要用人,只能使用对方的本性,很难改变他的个性~~~

因此,到最后俺就演变成了一直顺着对方的思路走下去,关键的时候给个小限制,只要把事做好,让结果为正确满意的即可,过程弯一点无所谓的啦~~~

俺闪人了,面对大师,俺只有认真听课的份~~~

LZ有机会,多看看高人写的程序风格特别是外国朋友写的格式,往往都非常正规,对你提升综合编程能力,大有好处,祝你心想事成~~~

使用特权

评论回复
77
ayb_ice| | 2011-3-1 20:07 | 只看该作者
人家LZ都结帖了,这边还在讨论

使用特权

评论回复
78
XIANSir|  楼主 | 2011-3-1 20:21 | 只看该作者
本帖最后由 XIANSir 于 2011-3-1 20:34 编辑

75# 刘前辈
75# 刘前辈
“唉!开玩笑呢,位域 pin.b_1,……不是位变量! 是你自己定义的uchar 变量!所以运算中采用的字节变量运算代码是编译器听你的话才编译出来的。 uchar  pin.b_1 本来就是按字节运算的,和整提升根本无关!”

前辈说的是,可能我在这里“乱用类型提升”这个概念了,其实,我说类型提升时,意思是指:~pin.b_1并不是对“位pin.b_1”进行按位取反操作,而是把这个位放在一个8位寄存器中然后对这个字节进行按位取反操作。
把一个位扩展成一个8位变量,我自认为这就是“类型提升”,至少在概念上这讲的通,但是类型提升的具体定义中是否认为这是类型提升,我就不得而知了——我没有读过C语言标准。

还有一点需要注意:进行运算时,并不是在字节pin上进行的,而是切切实实的将pin.b_1扩展到一个临时变量(寄存器)中得到的字节变量。

至于前辈说的类型提升至少是提升的int型,那不知道下面这个算不算类型提升啊??:

bit b1 = 0;

bit b2 = 1;

uchr b = 0;


b = (uchr)b1+(uchr)b2;

使用特权

评论回复
79
XIANSir|  楼主 | 2011-3-1 20:25 | 只看该作者
76# 123jj
谢谢指点。

能够总顺着别人的脾气思路来,看来你一定是个好脾气的人,做你这样的领导的下属应该是挺不错的。

使用特权

评论回复
80
XIANSir|  楼主 | 2011-3-1 20:32 | 只看该作者
本帖最后由 XIANSir 于 2011-3-1 20:38 编辑

75# 刘前辈
逻辑运算需要操作数整提升?你从哪看来的?自己别创新!还那么肯定地,最好先看看《C语言详解》有关内容,百度上搜索一下也行。”


那我请问前辈:如果一个32位的CPU,但是指令集中只有“字加”指令ADD,没有(不支持)字节相加指令——虽然我见识浅薄,不知道这样的CPU,但是这样的CPU肯定存在(比如,对于有符号字节变量的加法,不可能直接放到32位的寄存器中进行相加的,除非有特殊的硬件结构能够检测到加法过程中的的字节进位、双字节进位——就如51单片机中的psw寄存器中的cy位的作用一样)


那么:

byte a = 1,
         b = 1,c;
c = a+b;


你认为编译器会怎么处理啊??


我认为编译器会先把a和b都提升为4字节的字类型,然后进行相加,最后把结果的最低字节赋值给c


您认为a运算之前先扩展成字类型,这种现象叫做类型提升 吗???

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则