打印

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

[复制链接]
楼主: 程序医人
手机看帖
扫描二维码
随时随地手机跟帖
21
nongfuxu| | 2011-1-10 16:06 | 只看该作者 回帖奖励 |倒序浏览
unsigned int a;    a=(168*196)/10,结果a=62276

那是编译器害臊,怕生人,一慌张就出错了. 而10楼的,与它约定成熟,不那么害臊了,所以得出正解了.;P

使用特权

评论回复
22
nongfuxu| | 2011-1-10 16:08 | 只看该作者
这个问题,实在是应该问孩子它妈!:lol
当时怎么生出这样的编译器来,而且许多编译器都有这样的毛病.

使用特权

评论回复
23
joyo00321949| | 2011-1-10 16:52 | 只看该作者
看看  呵呵

使用特权

评论回复
24
fzu_csc| | 2011-1-10 17:11 | 只看该作者
unsigned int a;    a=(168*196)/10;  结果a=62276,较真实结果大很多。
//赋值语句,字符型赋值给整型,不提示出错么?

而改成:unsigned int a;   a=168*196; a=a/10; 结果是a=3292;
//第一条指令,整型变量赋值,正确
//第二条指令,除法运算,正确

使用特权

评论回复
25
nongfuxu| | 2011-1-10 18:36 | 只看该作者
LS的意思是,孩子他妈认定
      a=168*196/10 是字符型赋值,所以出错.
         a=168*196是INT变量赋值,所以正确.
看样子,我是对孩子他妈的赋值默认定义没有完全领会要领了.

使用特权

评论回复
26
程序医人|  楼主 | 2011-1-10 18:41 | 只看该作者
24楼,字符赋给整型是没问题的,这是大家伙都知道的。   再次说,在VC中这个语句是正确的。   难道这真是孩子他妈搞的鬼?

使用特权

评论回复
27
程序医人|  楼主 | 2011-1-10 18:59 | 只看该作者
呵呵,LZ真逗,PUSH 0 是C51语句么?( 可别跟我说uV4 _PUSH_ )看清楚,我写的是aaa.A51.
无论 PUSH   0 还是  PUSH   AR0 都是keil 51汇编语句,和C51有什么关系?
AR0~AR7是keil_Ax51宏汇编器的保留关键字,USING ...
刘前辈 发表于 2011-1-10 14:57


前辈所言极是。是我表达不到位,我想当初应该这样问,既然工作寄存器有名字了,能用寄存器对其寻址了,那么为什么还要给其编址,还不给用PUSH Rn。  莫非是为了减少指令数量(这样一来PUSH Rn指令就可省去)?

使用特权

评论回复
28
hgjinwei| | 2011-1-10 20:50 | 只看该作者
本帖最后由 hgjinwei 于 2011-1-10 20:51 编辑

(168 * 196)/ 10 = 0x80A0 / 10 = -32608 / 10 = -3260 = 0xF344 = 62276;

OVER, 编译器就是这么想的。

使用特权

评论回复
29
nongfuxu| | 2011-1-11 10:14 | 只看该作者
看样子,编写程序还真的应该多多注意这样的细节.
不了解孩子他妈想什么,还真的是遇到这样的问题还没有办法解开了.

使用特权

评论回复
30
liudan_new| | 2011-1-11 11:43 | 只看该作者
本帖最后由 liudan_new 于 2011-1-11 12:38 编辑
我怀疑是在(168*196)/10时编译器直接把浮点数的编码赋值给了x,所以存入x中的是浮点数编码,导致出错。
程序医人 发表于 2011-1-10 14:50

有可能。

使用特权

评论回复
31
刘前辈| | 2011-1-11 19:18 | 只看该作者
把运算过程说明为无符号数运算,—— 不是强制类型转换uint:

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


/

使用特权

评论回复
32
程序医人|  楼主 | 2011-1-11 20:48 | 只看该作者
前辈! 那为何写成这样可以:   a=(168*196);/*没说明运算有无符号*/     a=a/10;  /*亦未说明有无符号*/

使用特权

评论回复
33
刘前辈| | 2011-1-11 21:49 | 只看该作者
计算机内部算法是这样进行的:
a=0xA8*0xC4=0x80A0;
32位可能表达为 0xFFFF80A0= - 32608;  // 库函数错了吗?可以调出来看看。
你需要的是 0x000080A0=32928;
所以应说明为(unsigned )。

VC是16位基本单元的,( 168^196 ) 机器内部计算0x00A8*0x00C4=0x000080A0; 所以不用说明。

当然还应该把库函数_CDIV...源代码看一看。若是编译器在做,可就看不到了,只好照此推测。

使用特权

评论回复
34
STM32W108| | 2011-1-11 22:18 | 只看该作者
本帖最后由 STM32W108 于 2011-1-12 08:20 编辑

第二个问题,C语言基本功。

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

为什么结果是62276?
为了解答这个问题,我们先看下面几个问题。

1、168,196,10是什么类型??
答案:int。根据C语言标准,字面值整型常量,10进制且没有尾缀,能够在int表示的,都是int型。

2、int型与int型运算,包括+-*/,结果是什么类型?
答案:int。根据C语言标准,int与int进行算术运算,结果类型还是int。

3、如果int是16位,168*196结果是什么类型,结果值是多少?
答案:结果类型是int,值是-32608,16进制表示0x80A0。

4、-32608/10结果类型是什么?值是多少?
答案:结果类型是int,值是-3260,16进制表示0xF344。

5、unsigned int a; a=-3260;
结果a的值是多少?
答案:a的值是62276.

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
程序医人 + 1 这样啊
35
highgear| | 2011-1-11 22:25 | 只看该作者
“VC是16位基本单元的“, 这是想当然的胡扯。

编译器默认整数为 int 类型, 而不同的编译器对待 int 也不同, vc++ 中的 int 为32bit, Borland C++以及大多数嵌入式编译器 int 为 16bit,  做算术运算, 一定要对数制运算转换有清晰的概念, 要注意正整数的溢出问题, 很多普通 cpu 没有自动防止溢出的功能。

168*196 超过了16 bit 正整数 (32767)的上限而变为负数: -32608, 并没有超过32bit 正整数 (0x7FFFFFFF) 的上限.

要注意编译器在计算=右边的表达式时不会理会 =左边的数据类型, 只有在最后赋值时才会做类型转换.
所以,最好人工指定表达式的类型, 也可使用 L, ul, f 等数据后缀, 清晰而不易出错。

使用特权

评论回复
36
STM32W108| | 2011-1-11 22:46 | 只看该作者
本帖最后由 STM32W108 于 2011-1-12 08:21 编辑

补充:
A=B*C;
是先运算B*C的结果,在把结果赋值给A。改变A的类型,无法影响B*C运算是否溢出。如果B*C有溢出,A就是定义成10000位,也一样会溢出, A定义再多位,也无济于事。

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
程序医人 + 1
37
STM32W108| | 2011-1-11 22:52 | 只看该作者
本帖最后由 STM32W108 于 2011-1-11 22:54 编辑
………………
要注意编译器在计算=右边的表达式时不会理会 =左边的数据类型, 只有在最后赋值时才会做类型转换.
………………

highgear 发表于 2011-1-11 22:25


这才是关键点。

使用特权

评论回复
38
nongfuxu| | 2011-1-12 11:58 | 只看该作者
highgear说的好,有时候这些细节特别容易忘记,到调程序出现问题才会想起那些"约定俗成".

使用特权

评论回复
39
fzu_csc| | 2011-1-12 15:32 | 只看该作者
25# nongfuxu
写错了,说的是浮点,不是字符

使用特权

评论回复
40
xld0932| | 2011-1-15 11:31 | 只看该作者
34楼给力:victory:

使用特权

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

本版积分规则