Keil C51是与ANSI C兼容的编译器,ANSI C标准规则十进制整数常量的默许数据类型是int、long int和unsigned long int的其间一种,对给定的常量是其间的哪一种要看这个常量的实践巨细,假如常数在-32768~32767之间则按int类型处理,假如按int类型处理睬溢出就考虑long int或更大的数据类型unsigned long int。总归,编译器总是按尽或许的准则指定常量的类型。
但这一准则并不总能见效,当两个常量做运算时就或许导致溢出。如:
#define SYSCLK
#define SLIDER_REST_TIME
#define REST_DELAY
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 SYSCLK
注:尽管只要将22118400、100、65536和1000四个常数中的一个指定为无符号长整型即可得到正确的成果,但考虑到可读性及标准性,应挑选大整数指定其类型。
小结:按C51编译器的默许类型整数常量运算或许呈现溢出过错,对大整数应指定其数据类型以防止呈现或许的运算过错。
转自:幽幽灵猫
uint16
time
实践运转时,60s守时总是感觉不到,也便是说60s根本就没界说成功。
理论上讲,time
time
问题处理。
但仍未彻底理解其间道理,莫非是编译器的问题,在此抛砖引玉,不才虽然也有几年程序经历,但哎,偏偏这么一个看似基础性的东西却不明白,
编程中无量大常量的设定技巧2012年11月22日 13:08:05
转自
假如问题中各数据的规模清晰,那么无量大的设定不是问题,在不清晰的情况下,许多程序员都取0x7fffffff作为无量大,由于这是32-bit int的最大值。假如这个无量大只用于一般的比较(比方求最小值时min变量的初值),那么0x7fffffff确实是一个完美的挑选,可是在更多的情况下,0x7fffffff并不是一个好的挑选。
- 许多时分咱们并不仅仅单纯拿无量大来作比较,而是会运算后再做比较,例如在大部分最短途径算法中都会运用的松懈操作:
if (d[u]+w[u][v]咱们知道假如u,v之间没有边,那么w[u][v]=INF,假如咱们的INF取0x7fffffff,那么d[u]+w[u][v]会溢出而变成负数,咱们的松懈操作便出错了,更一般的说,0x7fffffff不能满意“无量大加一个有穷的数仍然是无量大”,它变成了一个很小的负数。 - 除了要满意加上一个常数仍然是无量大之外,咱们的常量还应该满意“无量大加无量大仍然是无量大”,至少两个无量大相加不应该呈现灾难性的过错,这一点上0x7fffffff仍然不能满意咱们。
所以咱们需求一个更好的家伙来替代0x7fffffff,最谨慎的方法当然是对无量大进行特别处理而不是找一个很大很大的常量来替代它(或者说模仿它),可是这样会让咱们的编程进程变得很费事。在我读过的代码中,最精巧的无量大常量取值是0x3f3f3f3f,我不知道是谁最早开始运用这个精妙的常量来做无量大,不过我的确是从一位不认识的ACMer(ID:Staginner)的博客上学到的,他/她的许多代码中都运用了这个常量,所以我自己也尝试了一下,发现十分好用,而当我对这个常量做更深化的剖析时,就发现它真的是十分精巧了。
- 0x3f3f3f3f的十进制是1061109567,也便是10^9级其他(和0x7fffffff一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无量大运用而不致呈现数据大于无量大的景象。
- 另一方面,由于一般的数据都不会大于10^9,所以当咱们把无量大加上一个数据时,它并不会溢出(这就满意了“无量大加一个有穷的数仍然是无量大”),事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这十分大但却没有超越32-bit int的表明规模,所以0x3f3f3f3f还满意了咱们“无量大加无量大仍是无量大”的需求。
- 最终,0x3f3f3f3f还能给咱们带来一个意想不到的额定优点:假如咱们想要将某个数组清零,咱们一般会运用memset(a,0,sizeof(a))这样的代码来完成(便利而高效),可是当咱们想将某个数组悉数赋值为无量大时(例如处理图论问题时邻接矩阵的初始化),就不能运用memset函数而得自己写循环了(写这些不重要的代码真的很苦楚),咱们知道这是由于memset是按字节操作的,它可以对数组清零是由于0的每个字节都是0,现在好了,假如咱们将无量大设为0x3f3f3f3f,那么奇观就发生了,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存悉数置为无量大,咱们只需求memset(a,0x3f,sizeof(a))。
所以在一般的场合下,0x3f3f3f3f真的是一个十分棒的挑选。