您的位置 首页 硬件

keil大常量核算问题

KeilC51是与ANSIC兼容的编译器,ANSIC规范规定十进制整数常量的默认数据类型是int、longint和unsignedlongint的其中一种,对给

Keil C51是与ANSI C兼容的编译器,ANSI C标准规则十进制整数常量的默许数据类型是int、long int和unsigned long int的其间一种,对给定的常量是其间的哪一种要看这个常量的实践巨细,假如常数在-32768~32767之间则按int类型处理,假如按int类型处理睬溢出就考虑long int或更大的数据类型unsigned long int。总归,编译器总是按尽或许的准则指定常量的类型。

但这一准则并不总能见效,当两个常量做运算时就或许导致溢出。如:
#define SYSCLK22118400// SYSCLK in Hz (22.1184 MHz external crystal oscillator)
#define SLIDER_REST_TIME100// in ms,slider rest time
#define REST_DELAYSYSCLK * SLIDER_REST_TIME / (65536 * 1000)
unsigned char i;
i = REST_DELAY;
keil c51中运转i为0xE1,即225,并不是期望的成果22118400 * 100 / (65536 * 1000) = 33.75,取整为33。原因剖析如下:
宏替换后为:i = 22118400 * 100 / (65536 * 1000);,编译器首先为22118400界说类型,由于22118400不在int的表明规模内,而在long int的规模-2147483648~2147483647内,所以22118400按long int类型处理,在做乘积运算时100被主动按long int处理,22118400 * 100将按两带符号长整型常量进行运算,运算成果仍为带符号长整型,成果写成十六进制是0x83D60000,其十进制是-2083127296,明显呈现了溢出过错。keil编译器并没有给出任何过错或正告提示信息(VC++6.0还给出正告warning C4307: * : integral constant overflow),继续进行下一个运算65536 * 1000,成果为带符号长整型,十六进制为0x3E80000,十进制为65536000,最终按两长整型除法核算-2083127296 / 65536000,成果为0xFFFFFFE1,由于i为字符类型,取0xFFFFFFE1的最低有用字节为0xE1赋值给i,i的最终值为0xE1。
处理这种溢出过错的方法用C言语的一个术语便是“提高”(promotion),拿上例来说便是将22118400指定为无符号长整型,即:
#define SYSCLK22118400UL
注:尽管只要将22118400、100、65536和1000四个常数中的一个指定为无符号长整型即可得到正确的成果,但考虑到可读性及标准性,应挑选大整数指定其类型。
小结:按C51编译器的默许类型整数常量运算或许呈现溢出过错,对大整数应指定其数据类型以防止呈现或许的运算过错。

转自:幽幽灵猫

http://www.cnblogs.com/civet/archive/2011/05/31/2064959.html
/////////////
近来做射频体系,一个简略的MCU体系,程序悉数用C言语规划,开发环境为盗版的Keil,用到守时器界说一个60秒的时刻时,如此界说:
uint16time;//16位变量

time=60*1000/TMRCYC//TMRCYC=5,守时器中止距离为5ms
//time总时刻60s
实践运转时,60s守时总是感觉不到,也便是说60s根本就没界说成功。
理论上讲,time=12000,比16位最大值65535小,应该没问题,但实践便是不可,曾经没怎么用过Keil,所以也没留意这个问题,是否其他编译器也有这个问题不得而知,最终,界说改为:
time=60*1000L/TMRCYC//常量1000后加L
问题处理。
但仍未彻底理解其间道理,莫非是编译器的问题,在此抛砖引玉,不才虽然也有几年程序经历,但哎,偏偏这么一个看似基础性的东西却不明白,期望有大虾们解说下,或许对你们来说问题很简略,但不明白或没有遇见的小菜们却是有千千万万,你们就权当做好事了。

///http://bbs.21ic.com/icview-43268-1-1.html
///
上一篇下一篇共25篇

编程中无量大常量的设定技巧2012年11月22日 13:08:05

转自http://aikilis.tk/

假如问题中各数据的规模清晰,那么无量大的设定不是问题,在不清晰的情况下,许多程序员都取0x7fffffff作为无量大,由于这是32-bit int的最大值。假如这个无量大只用于一般的比较(比方求最小值时min变量的初值),那么0x7fffffff确实是一个完美的挑选,可是在更多的情况下,0x7fffffff并不是一个好的挑选。

  1. 许多时分咱们并不仅仅单纯拿无量大来作比较,而是会运算后再做比较,例如在大部分最短途径算法中都会运用的松懈操作:
    if (d[u]+w[u][v]咱们知道假如u,v之间没有边,那么w[u][v]=INF,假如咱们的INF取0x7fffffff,那么d[u]+w[u][v]会溢出而变成负数,咱们的松懈操作便出错了,更一般的说,0x7fffffff不能满意“无量大加一个有穷的数仍然是无量大”,它变成了一个很小的负数。
  2. 除了要满意加上一个常数仍然是无量大之外,咱们的常量还应该满意“无量大加无量大仍然是无量大”,至少两个无量大相加不应该呈现灾难性的过错,这一点上0x7fffffff仍然不能满意咱们。

所以咱们需求一个更好的家伙来替代0x7fffffff,最谨慎的方法当然是对无量大进行特别处理而不是找一个很大很大的常量来替代它(或者说模仿它),可是这样会让咱们的编程进程变得很费事。在我读过的代码中,最精巧的无量大常量取值是0x3f3f3f3f,我不知道是谁最早开始运用这个精妙的常量来做无量大,不过我的确是从一位不认识的ACMer(ID:Staginner)的博客上学到的,他/她的许多代码中都运用了这个常量,所以我自己也尝试了一下,发现十分好用,而当我对这个常量做更深化的剖析时,就发现它真的是十分精巧了。

  1. 0x3f3f3f3f的十进制是1061109567,也便是10^9级其他(和0x7fffffff一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无量大运用而不致呈现数据大于无量大的景象。
  2. 另一方面,由于一般的数据都不会大于10^9,所以当咱们把无量大加上一个数据时,它并不会溢出(这就满意了“无量大加一个有穷的数仍然是无量大”),事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这十分大但却没有超越32-bit int的表明规模,所以0x3f3f3f3f还满意了咱们“无量大加无量大仍是无量大”的需求。
  3. 最终,0x3f3f3f3f还能给咱们带来一个意想不到的额定优点:假如咱们想要将某个数组清零,咱们一般会运用memset(a,0,sizeof(a))这样的代码来完成(便利而高效),可是当咱们想将某个数组悉数赋值为无量大时(例如处理图论问题时邻接矩阵的初始化),就不能运用memset函数而得自己写循环了(写这些不重要的代码真的很苦楚),咱们知道这是由于memset是按字节操作的,它可以对数组清零是由于0的每个字节都是0,现在好了,假如咱们将无量大设为0x3f3f3f3f,那么奇观就发生了,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存悉数置为无量大,咱们只需求memset(a,0x3f,sizeof(a))。

所以在一般的场合下,0x3f3f3f3f真的是一个十分棒的挑选。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/yingjian/257909.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部