打印

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

[复制链接]
楼主: XIANSir
手机看帖
扫描二维码
随时随地手机跟帖
81
俺没有读过C语言标准。

但俺知道,位域是一种特殊的数据形式,如你定义char数据类型中的几位为位域,实际上这几位位域都是char数据类型,只是以压缩存储的方式,存储在char数据类型中的一个BIT位,减少内存占用。

在你进行位赋值或判断时,严格的说,这每一位域变量(char型)都应该进行强制数据类型(bit型)变换,将“char型”转换成“bit型”!这符合C语言风格。
如你不加强制数据类型(bit型)转换,有时编译器能自动识别,有时编译器不能自动识别,刚出错。

对位域变量(char型)求反,必须加入强制数据类型(bit型)转换,否则出错。
如:pin.t_4 = ((~(bit)pin.b_1) && (~(bit)pin.b_2));
但人们常常简化成如下等价书写,直接判位域变量(char型)的真伪,运行结果一致。
      pin.t_4 = ((!pin.b_1) && (!pin.b_2));

而对位(bit型)求反,由于本身是bit型变量,则不必进行强制数据类型(bit型)转换。
如:
bit b1 = 0;
bit b2 = 1;
pin.t_4 = ((~b1) && (~b2));

使用特权

评论回复
82
123jj| | 2011-3-1 21:00 | 只看该作者
对bit型变量,无论你怎么用,用在何处,(~b1) 和(~b2)永远正确,等价于对b1 和b2 的真伪判断(!b1) 和(!b2) 。

使用特权

评论回复
83
123jj| | 2011-3-1 21:11 | 只看该作者

那么:
byte a = 1,
         b = 1,c;
c = a+b;

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

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

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

但是指令集中只有“字加”指令 ...
XIANSir 发表于 2011-3-1 20:32



这个问题又是不是问题的问题,根本不成立。

C编译器内部运算是直接调用合适的子程序,即机器码(汇编)方式按既定方针运行计算,不存在什么数据类型提升之说~~~

不过你的理解是对的~~~

使用特权

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

81# 123jj
位域是一种特殊的数据形式,如你定义char数据类型中的几位为位域,实际上这几位位域都是char数据类型,只是以压缩存储的方式,存储在char数据类型中的一个BIT位,减少内存占用。”


这个见解我还是第一次听说啊,想想好像挺对的,记下。。。。好好体会下

使用特权

评论回复
85
123jj| | 2011-3-1 21:16 | 只看该作者
呵呵!

LS别笑话俺,俺不懂C语言,俺没读过什么C语言标准。

只是,根据对C语言的一知半解,想不出怎样对你解说,只能用最原始底层的C编译器基本实现原理来对你述说~~~

使用特权

评论回复
86
XIANSir|  楼主 | 2011-3-1 21:23 | 只看该作者
83# 123jj
可是,不管编译器怎么调用子程序,最后的加法总得在CPU的ALU和寄存器上进行啊,这样就总会有我上面提到的问题啊。

把两个有符号字节数据放到32位的寄存器中进行运算,对于只支持32位加法的ALU,类型提升(默认类型转换)将是不可避免的。

使用特权

评论回复
87
123jj| | 2011-3-1 21:30 | 只看该作者
C语言博大精深,有时很绕口,通过LZ的这个贴子,俺确实学到和巩固了不少知识,这是真实的,不是谦虚,不是故事。

俺有个特点,善于现买现卖,前学后用,即兴发挥,这次自我感觉,发挥的不错,没有穿帮,呵呵! :lol

不过俺发现,春哥这方面的能力比俺更强,OO这方面的能力也不错~~~

使用特权

评论回复
88
XIANSir|  楼主 | 2011-3-1 21:34 | 只看该作者
81# 123jj
位域是一种特殊的数据形式,如你定义char数据类型中的几位为位域,实际上这几位位域都是char数据类型,只是以压缩存储的方式,存储在char数据类型中的一个BIT位,减少内存占用。”


越想越觉得这句话有道理,位域其实是“用起来(在C语言中)像位变量(bit),运算采用的却是整数行为方法”。


看来位域和bit的确有很大的区别啊,也不能像bit那样简单的认为等同于bool类型,因为位域竟然支持算术运算和移位运算,而这些都是bit和bool不支持的。


看来,虽然在使用上把位域当作bool类型比较安全——对位域使用bool类型的操作结果是安全、可预知的。但真正深入理解位域的话,还得从整型类型来考虑位域的行为啊。


这次讨论,真得使我学到了很多东西。非常感谢123jj前辈的热心指点

使用特权

评论回复
89
123jj| | 2011-3-1 21:37 | 只看该作者
83# 123jj
可是,不管编译器怎么调用子程序,最后的加法总得在CPU的ALU和寄存器上进行啊,这样就总会有我上面提到的问题啊。

把两个有符号字节数据放到32位的寄存器中进行运算,对于只支持32位加法的ALU,类型提 ...
XIANSir 发表于 2011-3-1 21:23



前面俺已经说过了,不存在什么数据类型提升(类型转换)之说~~~

不过你的理解是对的~~~

至于不叫数据类型提升(类型转换),而应该称作什么?俺也不知,因为只有高级语言(如C语言)有数据类型提升(类型转换)之说,汇编语言没有数据类型提升(类型转换)之说,怎么表达才合理,希望你好好想想,不要说出来又被二姨家的大师笑话~~~

使用特权

评论回复
90
XIANSir|  楼主 | 2011-3-1 21:41 | 只看该作者
89# 123jj
呵呵,C语言学的不好,只是通过学习单片机顺便学的,没有专门学习过,看来前段时间买的那本C语言的书没白买,接下来还是好好看看吧,不然又乱套名词,叫人笑话了。

使用特权

评论回复
91
123jj| | 2011-3-1 21:45 | 只看该作者
呵呵,共同学习,共同进步~~~ :victory:

使用特权

评论回复
92
123jj| | 2011-3-1 21:50 | 只看该作者
LZ的这句话:
位域其实是“用起来(在C语言中)像位变量(bit),运算采用的却是整数行为方法”。

应改为:
位域其实是“用起来(在所有高级语言中)像位变量(bit),运算采用的却是整数行为方法”。
比较适当~~~

使用特权

评论回复
93
xiaoding18| | 2011-3-1 22:02 | 只看该作者
向各位大师学习了~~

使用特权

评论回复
94
xuyaosong| | 2011-3-1 22:06 | 只看该作者
学习了,主要是不同运算符的应用,位域的操作

逻辑运算
&&逻辑与 ||逻辑或 !逻辑非
C语言允许直接对数字或字符进行逻辑运算。


按位运算
&:按位与运算符。
|:称为按位或运算符。
^:按位异或运算符。
~:按位补运算符。
按位逻辑运算符,只能用于整型表达式。通常用于对整型变量进行位的设置、清零、取反、以及对某些选定的位进行检测。


编程者经常混淆两组运算符:(&&,||,!)和(&,|,^)。第一组是逻辑运算符,它的操作数是布尔型,而第二组则是位运算符,其操作数是位序列。在布尔型操作数中,只有两个数值,0或1。C语言规定,在逻辑运算中,所有的非0数值都看做1处理。而位序列则可以是有无符号的字符型,整型,长短整型等。在位运算中,是相应的位之间进行逻辑运算。因此,从逻辑上讲,位运算过程包含多个逻辑运算过程。通常,位运算操作数选择无符号型数据。



位域:可以对位域进行逻辑运算,等同于位;对位域进行其他运算时,应考虑其整数行为。

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
123jj + 1
95
123jj| | 2011-3-2 08:09 | 只看该作者
LS总结的不错,赞一个! :victory:

使用特权

评论回复
96
刘前辈| | 2011-3-2 09:40 | 只看该作者
本帖最后由 刘前辈 于 2011-3-2 09:46 编辑

123jj 好像忘了一个主要前提,就是LZ之所以用标准ANSI C 这么写,是为了方便以后移植。标准ANSI C没有 bit 类型,所以LZ只好这样,——这是标准C处理位变量方法。

所以,强调一句:LZ的指令系统没有 bit 类型。那么123jj下面的强制(bit)类型有什么意义?没这个关键字,连编译都通不过,更别说LZ的方便移植初衷了:(要不你定义一个 typedef    char    bit ; )
   pin.t_4 = ((~(bit)pin.b_1) && (~(bit)pin.b_2));

另一方面,如果这个C 能够处理bit 变量,这个问题还要做吗?
bit  pin.b_1;
bit  pin.b_2;
bit  pin.b_3;
……
……

或者:
bdata  pin;
sbit  pin.b_1=pin^0;
sbit  pin.b_2=pin^1;
sbit  pin.b_3=pin^2;
……
……

再用 Keil C51 编译看看,代码缩减到1/10不止吧?
还有,请问这时候的逻辑运算操作数 pin.b_1,……怎么不先提升为char了?

所以,在这个讨论中,不要再提及bit类型;——这里用的不是C51编译器,是通用的、可移植的ANSI C 编译器。这里只有bool类型(TRUE)/(FALSE)逻辑分量; bool类型不是bit类型!

LZ是不是给我们讲讲你是如何把一个&&运算符两边的bool类型提升/转换为char类型的?这是咱们中国人的创新,一定要好好证明一下。Keil绝对不行。


使用特权

评论回复
97
刘前辈| | 2011-3-2 10:47 | 只看该作者
看看什么叫逻辑运算,&&两边的逻辑运算分量是bool类型,既不是char也不是bit类型。

使用特权

评论回复
98
刘前辈| | 2011-3-2 11:16 | 只看该作者
本帖最后由 刘前辈 于 2011-3-2 11:17 编辑




呵呵,bool 分量可以是任何类型——char , int , long,那么请教:提升到什么类型为好?

使用特权

评论回复
99
XIANSir|  楼主 | 2011-3-2 11:40 | 只看该作者
本帖最后由 XIANSir 于 2011-3-2 11:42 编辑

97# 刘前辈

“是不是给我们讲讲你是如何把一个&&运算符两边的bool类型提升/转换为char类型的?这是咱们中国人的创新,一定要好好证明一下。Keil绝对不行。”

刘前辈,我一直都说的是对位域变量pin.b_1进行“按位取反”的时候有有“类型提升”!
所以您这里的验证代码把按位取反符号给去掉,当然看不到“类型提升了”,您加上按位取反再试试看:
pin.t_4 =( (~pin.b_1) && (~pin.b_2))

刘前辈应该看到我把“类型提升”给加了引号了,因为我前面在回复您时已经承认了:我是“滥用类型提升这个名词了”。那不叫类型提升,但是因为没有合适的词语来形容这种现象,并且这种现象与类型提升非常相似,所以我就把它叫做“类型提升了”——因为这样大家可能容易理解我说的话的意思:
在我的pin.t_4 =( (~pin.b_1) && (~pin.b_2))式子中参加逻辑与运算的实际上是(0xFF) && (0xFE)或者(0xFE && 0xFF)或者(0xFF && 0xFF)或者(0xFE & 0xFE)
别人如果问我:0xFF和0xFE哪里来的啊??
我当然可以说:是pin.t_4这一位被移动到了一个字节中,然后对这个字节进行按位取反得到的。
但是如果我说:pin.t_4类型提升到char类型变量,然后对这个char变量按位取反,这样别人不是更容易理解吗

当然了,错误在我:我不该不清楚“类型提升到底是什么”就乱用名词,当然了,一开始我也不知道我乱用了名称,是123JJ教导我,我才明白自己的错误的,所以,在123JJ教导我之前对您的回帖可能不理解,所以就胡乱点评了一通。
我在此郑重道歉,希望刘前辈大人不计小人过,毕竟我是个初出茅庐的新手,不懂的还很多,需要学习的还很多,希望今后能够多多听到21IC高人的教导

使用特权

评论回复
100
XIANSir|  楼主 | 2011-3-2 11:44 | 只看该作者
98# 刘前辈

这个资料非常好,以前不知道,今天学习了,非常感谢刘前辈如此耐心的教导。

使用特权

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

本版积分规则