打印

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

[复制链接]
楼主: XIANSir
手机看帖
扫描二维码
随时随地手机跟帖
121
XIANSir|  楼主 | 2011-3-5 13:26 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
说过不发表评论的,还是乱放了一通,
其实是因为怕只发图片的话刘前辈会误会俺的用意,所以下面才乱说一气。

唉,这次说话没算数,下不为例

使用特权

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

为了防止挨骂。
俺再次确认:120楼的现象不叫类型提升。

至于这种现象到底叫什么,俺这菜鸟不知道,

使用特权

评论回复
123
刘前辈| | 2011-3-5 13:46 | 只看该作者
太棒了,LZ终于替前辈说明了题意。
(~(bit) pin.b_1 ) , 理解非常到位。就是不能移植到ARM  C。

如若能用 bit 类型,还用得着 C超高手 来讲课?LZ公司里有的是人才。

使用特权

评论回复
124
STM32W108| | 2011-3-5 13:59 | 只看该作者
bitfiled是数量型,表示一个数值。
而bool是布尔型,非0即真,表示逻辑真假。

数值型变量赋值采用的是高位截断。
比如说,把unsigned int赋值给unsigned char,那么高字节会被截断。
同理,对bitfield赋值,高位也会被截断。
假定x是只有一位的bitfield,
x=2;
x只有一位,2的高位被截断,保留最低一位,0,
相当于
x=0。

假定y是bool型,
y=2;
相当于
y=(bool)2;
2不为0,即真,
y=2最终结果相当于y=1;

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
123jj + 1
125
XIANSir|  楼主 | 2011-3-5 14:03 | 只看该作者
123# 刘前辈
偶!原来刘前辈一直想教给俺的是这个意思啊。俺的理解力实在是太差了,竟然没有理解刘前辈的良苦用心,直到这里才理解刘前辈的教诲。看来俺真是太笨了,俺要面壁思过去:'(


另外,俺对123JJ前辈是非常感谢、非常感激的——像感激您一样感激123JJ前辈

使用特权

评论回复
126
刘前辈| | 2011-3-5 14:34 | 只看该作者
再谈整提升: 谈到&&运算符时,注意有一句“ &&两边甚至可以是不同类型。”言外还有一个意思:什么运算符两边必须是相同类型?——算数运算符+,-,* ,/ 两边必须是相同类型。 整提升的意思就是,当算术运算符两边的数据类型不相同时,较小的操作数类型必须扩展与较大的那个操作数类型相一致。举例: (~pin.b_2*123)=char*char=char; //两边类型一致,如果运算结果能用char装下,那么谁也不需要提升。编译器至少聪明到不会做画蛇添足的事。否则那个编译器只能淘汰。 再举个一般例子: (int)a=168*196)=(char*char); 本来*运算符两边也是char,不提升,但是右边是int,168*196=int; char 装不下,所以实际运算,两边的char 都先提升到int. 哈:如果 (char)a=168*196; 怎么样?ARM 我不知道,C51是谁也没提升,哪怕结果是错的。

使用特权

评论回复
127
刘前辈| | 2011-3-5 14:37 | 只看该作者
本帖最后由 刘前辈 于 2011-3-5 15:03 编辑

所以,有个高手网友总结的好,最新的C标准,已经没有整提升概念,它属于数据转换规则。

再看      (pin.b_2 * 321)=char * int  ;

按照上述转换规则,这里pin.b_2需要提升,见下图:

使用特权

评论回复
128
XIANSir|  楼主 | 2011-3-5 14:55 | 只看该作者
发现自己之前的总结完全错误,具体情况见楼主贴,非常感谢124楼使在下觉醒过来

使用特权

评论回复
129
刘前辈| | 2011-3-5 15:13 | 只看该作者

使用特权

评论回复
130
XIANSir|  楼主 | 2011-3-5 15:14 | 只看该作者
126# 刘前辈

“举例: (~pin.b_2*123)=char*char=char; //两边类型一致,如果运算结果能用char装下,那么谁也不需要提升。编译器至少聪明到不会做画蛇添足的事。”

刘前辈,如果CPU只支持32位乘法,而不支持8位乘法怎么办呢??

比如ARM中:

signed char i = -1;
这个数被存储在内存中肯定是0xFF。而当他被放到R0中进行计算时,R0中的内容肯定是0xFFFFFFFF

我知道这个不叫做类型提升,只是希望刘前辈不要总是误会我的意思,我一直说的都是这种现象,只是之前错误的把它叫做类型提升,当然,在刘前辈和123jj教导之后,俺已经知道这种现象不叫类型提升了。

使用特权

评论回复
131
123jj| | 2011-3-5 15:20 | 只看该作者
bitfiled是数量型,表示一个数值。
而bool是布尔型,非0即真,表示逻辑真假。

数值型变量赋值采用的是高位截断。
比如说,把unsigned int赋值给unsigned char,那么高字节会被截断。
同理,对bitfield赋值,高位也会被截断。
假定x是只有一位的bitfield,
x=2;
x只有一位,2的高位被截断,保留最低一位,0,
相当于
x=0。

假定y是bool型,
y=2;
相当于
y=(bool)2;
2不为0,即真,
y=2最终结果相当于y=1;...
STM32W108 发表于 2011-3-5 13:59



STM32W108老师讲解的非常透彻,让俺更进一步认清了数据类型的本质,谢谢!

使用特权

评论回复
132
123jj| | 2011-3-5 15:24 | 只看该作者
LZ位的总结相当给力,小伙子现学现抄现总结的能力不错,大有赶上OO的趋势,赞一个~~~  :P

使用特权

评论回复
133
XIANSir|  楼主 | 2011-3-5 15:30 | 只看该作者
本帖最后由 XIANSir 于 2011-3-5 15:44 编辑
126# 刘前辈  

“举例: (~pin.b_2*123)=char*char=char; //两边类型一致,如果运算结果能用char装下,那么谁也不需要提升。编译器至少聪明到不会做画蛇添足的事。”

刘前辈,如果CPU只支持32位乘法,而不支持8位 ...
XIANSir 发表于 2011-3-5 15:14


俺错了,刚才实验了一下,ARM的编译器不是这么干的,它竟然使用了下面这种做法:
把0xFF和1相加得到0x00000100,然后把这个数左移24位,然后右移24位,这样只留下了R0这个32位寄存器的低8位的值。

不过,120楼的帖子也能说明我的意思。
首先,我已经认识到刘前辈的指点的正确性,知道那不叫类型提升;但是,也希望刘前辈能够稍微理解我为什么之前一直说类型提升,因为那里的现象确实和类型提升比较相似,有点迷惑性(对您这样的高手肯定是没有迷惑性了):比如位域pin.b_1只有一位,但为什么按位取反后会得到0xFE呢??在ARM7上得到的又是0xFFFFFFFE呢??

使用特权

评论回复
134
XIANSir|  楼主 | 2011-3-5 15:35 | 只看该作者
131# 123jj
嗯,要是看不到STM32W108前辈上面的总结,俺就会记下一个根本性的错误结论,实在是非常非常非常感谢STM32W108前辈!

使用特权

评论回复
135
刘前辈| | 2011-3-5 18:20 | 只看该作者
本帖最后由 刘前辈 于 2011-3-5 19:28 编辑
比如位域pin.b_1只有一位,但为什么按位取反后会得到0xFE呢??在ARM7上得到的又是0xFFFFFFFE呢??

看来前辈的联想能力一流,有些话一直没说,说多了反而让人质疑。

第一,ANSI C 规定:位段结构是把16位的整型变量按位段定义成结构。举例:
struct
{
uchar  b_1:  1;
uchar  b_2:  1;
……
uchar    ……
uint      m:    8;
}pin=(1,0,……120};

C51上按LZ的写法定义了8位uchar 当然可以,( 8位机上可以移植)ANSI C 写法标准应该是16位,新的C标准有没有规定32位位段结构前辈还不知道。
        ARM一个int 如果32位,那么一个位段结构32位(不严格按照ANSI C)也能理解。看编译器自己怎么做方便了。

现在的问题: ~pin.b_1=0xFFFFFFFE ;
太好理解了,我前面说一个单个pin.b_1 连“运算对象”都不算,它提升个啥?(仔细看整提升定义:什么叫运算对象:只有运算对象才需要整类型 int 提升!)

       而现在你是 ~ pin.b_1 ,   ~ 是运算符,运算符后面的当然是运算对象,它可能提升(新的概念叫类型转换),也可能不需要提升,取决于它当前的类型是不是整类型 int 。你定义的是uchar, 所以ARM编译器规则需要转换为 int ,成为0x00000001;按位取反等于0xFFFFFFFE。

所以这里好几个需要理解的问题:
1、没有运算符的表达式pin.b_1 , 不是运算对象。

2、~ 是运算符。它后面的pin.b_1,是运算分量。

3、提升(转换)是较小的类型对象在“该用 int 类型的地方。”的扩展应用。

4、这种转换并不影响 运算对象的值。

5、写成更标准的形式,应该是:
struct
{
    int   b_1:  1;
     int   b_2:  1;
……
……
}




使用特权

评论回复
136
刘前辈| | 2011-3-5 20:03 | 只看该作者

使用特权

评论回复
137
lanmanck| | 2011-3-5 20:20 | 只看该作者
无聊也~~~~

使用特权

评论回复
138
XIANSir|  楼主 | 2011-3-5 20:59 | 只看该作者
135# 刘前辈

刘前辈啊,俺是好早就已经承认那不叫类型提升了,至少从这个帖子的第五页开始俺就没有再叫过这种现象叫做类型提升吧?

俺后来的跟帖只不过是想说:那种现象确实有点像类型提升,所以我这样的新手确实容易在此处犯糊涂。要是一点都不像,我却把那种现象说成是类型提升,那我不是智商有问题了吗??
所以,俺也希望前辈肯定俺的观点:确实有点像,从而俺好不老是怀疑俺的智商(这么低的智商搞单片机恐怕是一点希望都没有),为什么前辈就不能同情俺一下呢:'(

使用特权

评论回复
139
highgear| | 2011-3-5 21:12 | 只看该作者
刘工对技术的理解不到位,口水又多,把一个并不复杂的问题搞的乱七八糟。

1)ansi c 甚至没有规定 int 的宽度(这不是疏忽,而是特意如此), 更不会规定 bit field的宽度了。刘工联想能力一流,但技术就是技术,不能胡扯。ansic 只规定bit field使用 int 类型,即便这样,包括micosoft 还是不愿受此限制,扩展到了 char, long. bit field 是移植的阻碍,这是公论。

2)所谓“提升”, 我前面的帖子已经说的很明白了,关键是要理解 cpu 的特性以及 compiler 的行为。例如 char 类型, 为了最优, 32bit compiler 可能会以 32bit 形式处理, bool 亦是如此。

3) bool 也好, bit field 也好,甚至 char, short, int, float 在交互过程中存在一个转换过程, 并非直接赋值。做过 c++ 重载和隐式转换的就会很清楚。 例如 int a = 0x20; int b = (int)((bool) a);

使用特权

评论回复
140
XIANSir|  楼主 | 2011-3-5 21:13 | 只看该作者
本帖最后由 XIANSir 于 2011-3-5 21:26 编辑

上面说错了:不是从本帖的第五页开始,是从在第五页中的89楼123JJ前辈教育俺之后

使用特权

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

本版积分规则