OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5127|回复: 7

分享BUG-8位PIC的MCU的类型问题:unsigned long cnt=15*60*50;//理论为45000,实际为-20536

[复制链接]

5

主题

154

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
205
金钱
205
注册时间
2013-6-8
在线时间
2 小时
发表于 2014-10-18 10:48:53 | 显示全部楼层 |阅读模式
最近在做8位单片机的程序,真的是郁闷了,查了半天才查出这个问题,
现分享给大家,也提醒自己一定要注意MCU的位数和编译器和标准C之间的类型问题。

就是这个表达式15*60*50=45000, 0xAFC8

PC机上测试:
unsigned long cnt=15*60*50;
printf("cnt=%d,%#x",cnt,cnt);
//输出 45000,0xAFC8   结果正确没问题


8位单片机PIC16F1509上测试:sizeof(unsigned long)是等于4;
unsigned long cnt=15*60*50;
itoa(cnt, buf, 10);    dputs(buf);//转为10进制字符串
itoa(cnt, buf, 16);    dputs(buf);//转为16进制字符串
//输出结果:-20536, -5038
//-20536(10进制)=-5038(16进制)
//这结果碉堡了,我说我的程序老是不对劲

原因:
表达式结果是45000绝对没错,但是8位单片机居然会对这个数
做溢出处理,从32767溢出到-32768,再向上继续溢出,所以最终
结果就成了-20536。

解决方法,使用标准给每一个数都指明一下类型就OK了:
unsigned long cnt=15UL*60UL*50UL;

char *itoa(long val, char *buf, int radix)
{
    char *high, *low, tmp;
    int digit;
    high = buf;
    if (val < 0)        //判断符号
    {
        *high++ = '-';
        val = -val;
    }
    low = high;         //记录数字的低位所处的位置
    do                  //从个位开始分离,数字是反转的
    {
        digit = val % radix; //个位
        val /= radix;   //val向个位移动
        if (digit > 9)
            *high++ = (char)(digit - 10 + 'A'); //16进制
        else
            *high++ = (char)(digit + '0'); //10进制
    }
    while(val > 0);
    *high-- = '\0';     //添加结束符, high指向数字的高位,开始进行反转
    for (; low < high; low++, high--)
    {
        tmp   = *high;
        *high = *low;
        *low  = tmp;
    }
    return buf;
}
即使爬到最高的山上,一次也只能脚踏实地地迈一步。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-10-18 23:37:15 | 显示全部楼层
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

10

主题

561

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1841
金钱
1841
注册时间
2014-6-27
在线时间
982 小时
发表于 2014-10-20 11:33:21 | 显示全部楼层
很明显的事情,给第一个就可以了,其他自动跟着转。
回复 支持 反对

使用道具 举报

10

主题

561

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1841
金钱
1841
注册时间
2014-6-27
在线时间
982 小时
发表于 2014-10-20 11:35:34 | 显示全部楼层
如果能理解CPU的硬件运算器如何运算的,在那款单片机都是一样的。
回复 支持 反对

使用道具 举报

5

主题

154

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
205
金钱
205
注册时间
2013-6-8
在线时间
2 小时
 楼主| 发表于 2014-10-20 19:54:37 | 显示全部楼层
回复【4楼】TinyBoy:
---------------------------------
出现这样的编译器也只能认栽了,哎,谁会想到45000这样的数也会被溢出处理呢?
即使爬到最高的山上,一次也只能脚踏实地地迈一步。
回复 支持 反对

使用道具 举报

10

主题

561

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1841
金钱
1841
注册时间
2014-6-27
在线时间
982 小时
发表于 2014-10-21 08:05:01 | 显示全部楼层
回复【5楼】倒拔萝卜:
---------------------------------
你要做到在任何编译器上运算结果都是对了就行了。
回复 支持 反对

使用道具 举报

34

主题

805

帖子

4

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1865
金钱
1865
注册时间
2011-3-29
在线时间
140 小时
发表于 2014-10-21 14:38:07 | 显示全部楼层
回复【5楼】倒拔萝卜:
---------------------------------
不是bug,而是C标准就是这样。楼主对C了解还不够透彻。
默认整形是int,至于int是16bit还是32bit,就要看你的硬件平台了。15*60*50的结果如果是16bit的int类型,自然无法存放45000而溢出了。
业余程序玩家。
回复 支持 反对

使用道具 举报

5

主题

154

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
205
金钱
205
注册时间
2013-6-8
在线时间
2 小时
 楼主| 发表于 2014-10-21 14:58:28 | 显示全部楼层
回复【7楼】ofourme:
---------------------------------
不是不了解C标准,这个编程习惯很难改的,
写的时候谁又会在意这么个小小的表达式还会存在类型问题?
即使爬到最高的山上,一次也只能脚踏实地地迈一步。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-30 01:48

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表