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

终于明白 a = (168*196) / 10 ; 为什么诡异

[复制链接]
楼主: 刘前辈
手机看帖
扫描二维码
随时随地手机跟帖
41
刘前辈|  楼主 | 2011-1-18 14:24 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
本帖最后由 刘前辈 于 2011-1-18 14:47 编辑

哎呀,别打我,我躲。不是我胡扯,是书上在胡扯。



我这本书是89年以前出版的标准,当然管不着 C89 还是C99 。——别拿改进以后的标准说事!将来还会有C2019,我那时能说C99都是完全胡扯?

抄一段前言:
本书收集了覆盖K&R ·C,ANSI   C标准以及有关各种版本诸如 Microsoft   C, Quick   C, Turbo  C,  Borland  C++等的全部命令、功能、编程和应用,以及他们之间的比较等全部内容。
……
本书很适用于所有C使用者。


不仅这一本,还看过一本,最后一句说的是“……long 类型依此类推……”
现在的改进把这一段放到“算数转换”里去了。

先承认个错误,40楼是对的。书上说了:

“首先,……其次,……,再次,……再再次,……如果上述几种情况都不符合,那么两个操作数的类型都作为 int ,计算结果的类型也是 int 。”


168*196就是这种情况。还有0x7FFF *0x7FF =1;(胡扯了)也是这种情况。
long*long =int 也是这种情况?越乘越小了,无法处理,最后只好 转换为 int *int  ——合理地胡来了。

最基本的原理,2个操作数,运算前,较小的那个,其类型按照较大那个操作数类型自动转换,……运算结果类型也和最大那个操作数类型一致。

又要有人说胡扯了。建议:胡扯之前拿出证据,Original  Type 都包含什么类型讲清楚。

使用特权

评论回复
42
STM32W108| | 2011-1-18 15:03 | 只看该作者
本帖最后由 STM32W108 于 2011-1-18 15:09 编辑
最基本的原理,2个操作数,运算前,较小的那个,其类型按照较大那个操作数类型自动转换,……运算结果类型也和最大那个操作数类型一致。
刘前辈 发表于 2011-1-18 14:24


正确。
这叫算术转换,而不是整型提升。

C99标准规定+-*/ 运算符操作数类型至少为int。

如果操作数不满int,比如说char,如何运算呢?
C99标准要求 先把操作数提升至int或者unsigned int,再参与运算。
这样就能满足操作数类型至少为int的要求。

这才是整型提升。
这才有 char * char ,结果是int。

使用特权

评论回复
43
刘前辈|  楼主 | 2011-1-18 16:42 | 只看该作者
这样讲就大家受益了。我首先感谢43楼,几天来明白不少东西。自己看多少遍不一定有用的,——胡扯有益。

等一下我举一个 char*char=char; 的例子,说明C51不是C99。(不能算优化。)

还有: 程序医人的168*196=0x80A0;  的问题不能避而不谈。0xF344无论是用到整提升还是寻常算数转换,都得不到0xF344 的结果。也许最后确实是编译器问题。幸亏我没拿着有问题的编译器瞎说。

使用特权

评论回复
44
highgear| | 2011-1-19 03:17 | 只看该作者
本帖最后由 highgear 于 2011-1-19 03:25 编辑

诡异的事情一旦揭穿了,就会知道其实很简单,只是超出人们的惯性思维而已.
刘公,这么简单的问题需要大家给你讲多少遍。就像前面的那个 led与刷新率的关系这么一个简单问题,,在 xwj, 原野之郎,quakegod等等人的耐心解答下,刘公你仍然不明白,甚至没有去用实验验证(https://bbs.21ic.com/viewthread.php?tid=201387&highlight=led


最后还是我用技术帖来结帖吧
(168*196) / 0x10 与 0x80A0 >> 8, 的本质是 signed int 与 unsigned int 同一数值但不同的类型表达时,编译器运算结果的问题.

注意下面的几个16bit表达式的结果不同
((short) 0x80A0) /256 = 0xFF81 ;signed 除法为求正后整数除法最后加符号,即 0x80A0/256 =(-32608) /256 = -(32608/256) = -127 = 0xFF81
((unsigned short) 0x80A0) /256 = 0x0080; 无符号整数除法 32928 /256 = 128 = 0x0080
((short) 0x80A0) >> 8 = 0xFF80; 算数右移算数移位会保留最高位的符号位
((usigned short) 0x80A0) >> 8 = 0x0080; 逻辑右移

同样的, 还有一个16bit signed int 赋值到一个 32bit long时, 符号位扩展的问题。如 (short) 0x80A0 --> long = 0xFFFF80A0 等
同样 32bit 的移位
((long) 0xFFFF80A0) >> 8 = 0xFFFFFF80;  算数右移
((unsigned long) 0xFFFF80A0) >> 8 = 0x00FFFF80; 逻辑右移

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
123jj + 1
45
123jj| | 2011-1-19 07:49 | 只看该作者
highgear老师正解!
这么简单的基础问题,横过来讨论,竖过来讨论,俺这个菜鸟都看不懂,不知道讨论啥?!

使用特权

评论回复
46
yewuyi| | 2011-1-19 08:56 | 只看该作者
看大家的一堆口水,我晕了。。。


呵呵,不懂C语言的学童飘过。。。。。。

使用特权

评论回复
47
sdpz| | 2011-1-19 11:08 | 只看该作者
a = ( unsigned ) (168*196) / 10 ;

a = (( unsigned ) 168*196) / 10 ;

式子运算是按照第一个数的符号类型来算的。

使用特权

评论回复
48
leang521| | 2011-7-11 17:32 | 只看该作者
mark

使用特权

评论回复
49
无锡三子| | 2011-7-11 18:47 | 只看该作者
:)

使用特权

评论回复
50
sysdriver| | 2011-7-11 20:59 | 只看该作者
发表个人意见

专门找溢出立即数来写程序,是不是有点自作自受

使用特权

评论回复
51
XIANSir| | 2011-7-11 22:14 | 只看该作者
18# highgear
“-5000/256 整数除法, 实际上是 5000/256 后加符号, 即:整数除法
-5000/256 = -(5000/256) = - (19) = -19 = 0xFFED. ”

前辈,看到您这个说法我感觉很新颖——以前从未听说过,可是,您这种说法对我们有一定的误导吧,看到您的说法,我首先想到的是 负号(-)优先级比 除号(/)优先级低,可事实上二者的优先级是 负号 高于 除号。。

而且,我感觉:实际的运算应该也不是-(5000/256)这样子的吧。。。

菜鸟疑惑,请前辈指教!!!

使用特权

评论回复
52
highgear| | 2011-7-13 21:18 | 只看该作者
挖坟党很厉害啊。

回 XIANSir:
你的问题与C语言中的优先级无关,这涉及到除法运算的底层实现方法。普通计算机中的除法运算,无论软件除法还是硬件除法,最终使用 减法-移位 操作实现的,而这种底层操作不涉及分子分母的符号,或者说,分子分母都被作为无符号整数进行运算。因此,对于有符号除法,分子分母都必须先转换为正整数,最后把结果转为负整数,如果符号为负的话。这就是
-5000/256 = -(5000/256)  <---- 在 减法-移位 操作中的操作数为 5000 与 256

使用特权

评论回复
53
邪恶猛男| | 2011-9-11 10:10 | 只看该作者
糊涂 简单问题 看样子 你们脑袋智商到头了

使用特权

评论回复
54
nan_banqiu| | 2011-9-12 09:34 | 只看该作者
18 19楼直接牛人……

使用特权

评论回复
55
linqing171| | 2011-9-17 21:03 | 只看该作者
哈哈,什么都不懂的人路过。

使用特权

评论回复
56
jimmychen| | 2011-9-18 10:19 | 只看该作者
mark

使用特权

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

本版积分规则