发新帖我要提问
123
返回列表
打印

【技术问题】keil中的那些诡异事件。

[复制链接]
楼主: 程序医人
手机看帖
扫描二维码
随时随地手机跟帖
41
本帖最后由 刘前辈 于 2011-1-15 13:24 编辑

34楼讲得好。但是下面第3条再讲讲怎么回事,好像说不过去:
3、如果int是16位,168*196结果是什么类型,结果值是多少?
答案:结果类型是int,值是-32608,16进制表示0x80A0。


168*196=32928d=0x80A0;   -0x80A0=-32928d≠-32608d;

麻烦请教 -32608d是怎么来的?

/

使用特权

评论回复
42
刘前辈| | 2011-1-15 19:30 | 只看该作者
想通了。32928d=-32608d;  正像 255=-1;  一样。
谢谢34楼。

使用特权

评论回复
43
刘前辈| | 2011-1-17 10:58 | 只看该作者



这是C语言标准中“整提升+保符号/ 保值 规则的问题。”——当一个16位的int 值最高位(符号位)为1时,它也许是表示一个负数,或许是一个经过编译器自动整提升进位上来的正数,例如:168*196= 0x80A0; 它是由int自动整提升为unsigned int 的;符号位怎么办?——这就是整提升之后运用的保符号还是保值规则;有的编译器缺省使用保符号规则(默认丢掉的符号是1——负数标识),有些编译器缺省采用保值规则 (忽略丢掉的符号,默认为0——正数标识),还有些编译器更完善,可以由用户使用编译开关来选择保值还是保符号规则。举例:0xFF, 由于符号位为1,所以既可以翻译为255d (保值规则),又可以翻译为 -1d(保符号规则),两者都是对的。究竟采用什么规则,由用户决定。 像程序医人的例子,如果希望得到正数,就可以采用采用强制unsigned 告诉编译器采用保值规则;否则,希望得到负数,就采用默认(ANSI C 默认保符号规则。),这就是为什么168*196 会得到一个负数的原因,也是我上面加入 unsigned 的理由。

使用特权

评论回复
44
STM32W108| | 2011-1-17 12:46 | 只看该作者
本帖最后由 STM32W108 于 2011-1-17 13:00 编辑

楼上说了这么多,“整型提升”概念都没搞明白。

C语言标准对字面值整型常量的类型有明确规定,
这里的168,196本身就是int类型。

根据C语言标准,int与int相乘,结果类型只能是int,不可能是其他类型。


以下是C99关于整型提升的定义:
If an int can represent all values of the original type, the value is converted to an int;otherwise, it is converted to an unsigned int.These are called the integer promotions。


Image0095.JPG (20.32 KB )

Image0095.JPG

Image0096.JPG (26.87 KB )

Image0096.JPG

使用特权

评论回复
45
刘前辈| | 2011-1-17 18:21 | 只看该作者

有些明白了。

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

请教44楼:您是说先提升,后运算?(注意我们在讨论8位机上的运算。)那就更不好解释了,本来是8位*8位=int ,库函数已经很复杂,再放大为int*int=long ?  编译器不会看不出2个操作数都是8位的吧。我理解整提升情况是
    int  a * char  b  ,这时b需要提升到 int 。 uchar * uchar ,没有符号位问题,无需提升,编译器比人聪明。

还有一点:保值/ 保符号规则肯定是对最终计算结果实施的,并且必然是紧跟在整提升之后启动的。这一点没错吧?所以,我的逻辑理解:整提升也是对最终计算结果进行的,而不是对初始输入操作数进行的。否则,岂不是说:要对每个输入操作数实施保值/保符号规则?不可能不可能,舍易求难了。更不好解释:

168*196= -0x80A0 了;

因为: 0x 00A8*0x00C4=0x000080A0 ;   //  何来 - 0x80A0?
  或者0x07FFF* 0x7FFF= long ;   //  这才叫整提升?


趁着我们难以理解的时候,给咱们开导开导,我的实验结果哪一点不合理或者根本错了,麻烦具体指正。举几个例子才好。
我先举一个:
2个signed  char操作数 51和5,相乘,应为signed   int :
       51*5=255=0xFF;
signed   int  放不下,自动整提升为unsigned   int  ,然后施用保值 / 保符号规则。等于255 / -1 。用户取什么值“取决于具体实现”。

为什么是胡扯?

使用特权

评论回复
46
老郑电子| | 2011-1-17 18:30 | 只看该作者
我RI、程序医人,我还以为是程序匠人呢

使用特权

评论回复
47
STM32W108| | 2011-1-17 18:33 | 只看该作者
还有,您说一个运算符两边的操作数一定是int (我理解C51中int最小是16位)?那么上面说的char 一定是8位的吧,short int 也是8位的,8位*8位=16位(int) 这个没错吧。
    您说: int*int=int; ?????我这水平确实不能理解,数据压缩技术?
         32767*32767=(32位)=int 装得下吗?

所谓自动整提升,就是当一个运算符两边的较小的操作数经过运算后的自动放大扩展,以使得运算结果能够装得下。——如果你2个操作数是int, 那么计算结果应该是int*int=long。signed long 若装不下,就再放大为uL。然后按照用户要求,采用保值规则或者保符号规则处理这个uL。如果符号位为0,那么保符号规则不会被启用,因为L是正数。


刘前辈 发表于 2011-1-17 18:21


楼上你根本没去看C语言标准。
只在这里胡乱臆测。



使用特权

评论回复
48
STM32W108| | 2011-1-17 18:35 | 只看该作者
本帖最后由 STM32W108 于 2011-1-17 18:52 编辑

运算符两边的操作数一定是int
-------------------------------------------
算术运算符两边的操作数至少要为int。
或者是比int具有更高提升级别的类型,如unsigned int,long等。





说的char 一定是8位的吧,short int 也是8位的,8位*8位=16位(int) 这个没错吧。
----------------------------------------------------
*乘法算术运算符两边的操作数至少要为int,char * char,两边操作数都不满int,将自动转换成int(整型提升),最后结果是int。
整型提升的目的就是要满足算术运算符两边的操作数至少要为int的要求。


32767*32767=(32位)=int 装得下吗?
------------------------------------------------
楼上没把数学等式与C语言规则分清楚。
C语言里所有数据都有类型。两个数据进行运算,会按照他们的类型运算规则,得出结果。
而int*int,得到的结果永远是int型,不可能是其他类型。C语言标准如此。
如果int是16位,那么32767*32767的结果就是1,类型是int。




使用特权

评论回复
49
刘前辈| | 2011-1-18 11:22 | 只看该作者
明白一点了。最关键的问题是这道题还是说不过去。下面:(问了几次了)

168*196=0x80A0;

但是48楼大侠的等式 :168*196=0x80A0=-0x80A0;
无法解释。其实这道题的结果0xF344根本不靠谱,什么事不能硬往0xF344上套。
全错在-0x80A0这一步。我是不是也可以说:
168*196=-0x80A0;  是胡扯。

我准备好无地自容了。

使用特权

评论回复
50
csq463276932| | 2011-9-13 15:15 | 只看该作者
有深度,学习。

使用特权

评论回复
51
linqing171| | 2011-9-14 06:40 | 只看该作者
0x80A0的补码就是65536-0x80A0,也就是0-0x80A0;或者说是0x80A0的反码加1.

使用特权

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

本版积分规则