Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48500
  • 博文数量: 12
  • 博客积分: 145
  • 博客等级: 入伍新兵
  • 技术积分: 115
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-28 18:02
文章分类

全部博文(12)

文章存档

2013年(5)

2012年(7)

我的朋友

分类: LINUX

2012-12-27 10:21:28

这是转的一篇转载的文章,原文的链接没有在那篇文章中体现出来。表示遗憾。


做一道题,题目是通过试验的方法(即编写带有此类问题的程序)观察系统如何处理整数上溢、浮点数上溢和浮点数下溢的情况。”这一道题照说应该是很简单的,但是在做此题的时候关于INT取值范围方面出了一些小的插曲却花了我两天来了解。在这里,我想把我的心得与大家分享一下:

在解题时,要观察INT上溢情况,偷了一下懒,没有定义整型变量为32767,而是直接使用系统定义的常量INT_MAX。输入完毕编译运行时,满以为输入的会是我想象的32767和-32768。可是,得出结果却是出乎我意料之外的2147483647和-2147483648。这是什么情况呢。前者是16位INT,而后者却是32位的。怎么跟书上的不一样。

找几本书仔细查了一下,分别对INT取值范围有如下描述:

《C程序设计 (第二版)》谭浩强 著

P42:一个int型变量的值的范围为-215~(215-1),即-32768~32767。

P43:通常的做法是:把long定为32位,把short定为16位,而int可以是16位,也可以是32位。这主要取决于机器字长。

《The C programming Language, 2nd》中文版 Brian W.Kernighan &Dennis M.Ritchie著

P28: int 整数,一般反映了宿主机上整数的自然大小。

P28: int通常反映特定机器的自然大小,一般为16位或32位……

《C Primer Plus (第五版)》 中文版 Stephen Prata 著

P35:对于一种给定的计算机设计,字(word)是自然的存储单位。

P36: 一般地,int类型存储在计算机的一个字中……

P40:……int类型为16位或32位(依机器的自然字大小而定)

哦!原来是这样,三本权威的书里都说了int可以是16位或32位。看来我得出的结果32位的也没错啊。因为我的电脑就是32位的总线系统嘛,应该就可以结案了吧。

可是……慢着,不对啊,曾记否,在N年前,同样的电脑,为什么我得出的结果是16位的呢。记得当年总爱忘记,为了记这几个数也花了点精力的。因此映像深刻,这也是为什么先前我得出32位结果时小吃了一惊的原因。这到底是什么原因呢。故事因此展开……

打开浏览器,在google里搜索“int取值范围”,得到的结果不一而足。什么取值范围取决于系统(是什么系统也没说清,是操作系统还是编译系 统);取决于编译器;取决于机器等等。还有的说就是-32768~32767。看得让人头大。有没搞错,真像只有一个,怎么却有这么多不同的答案。这些人 中到底有几个是真懂的发贴来回答,还是照书死念或干脆特地来灌水?晕,求人不如求已。自己动手吧。

硬件:

CPU:闪龙2200+  

主板:nForce 2  

内存:512MB DDR400

系统:Windows XP(32位),Windows 3.2(16位)

虚拟机:Virtual PC(虚拟32MB内存)

编译器:GCC4.4.1,Turbo C 2.0

源码:#include

#include

int main(void)

{

   printf ("The max int is %d\n",INT_MAX);

   printf ("Max int plus 1 is %d\n",INT_MAX+1);

   printf ("The max unsigned int is %u\n",UINT_MAX);

   printf ("Max unsigned int plus 1 is %u\n",UINT_MAX+1);

   return 0;

}

默认头文件相关设置:

GCC 4.4.1    C头文件limits.h整数部分定义

/* Maximum and minimum values for ints. */

#define INT_MAX             2147483647

#define INT_MIN              (-INT_MAX-1)

#define UINT_MAX   0xffffffff

TC 2.0   C头文件limits.h整数部分定义

#define INT_MAX                    0x7FFF

#define INT_MIN                     ((int)0x8000)

#define UINT_MAX           0xFFFFU

测试一:32位电脑运行系统Windows XP

运行结果:

GCC 4.4.1

The max int is 2147482647

Max int plus 1 is -2147482648

The max unsigned int is 4294967295

Max unsigned int plus 1 is 0

Turbo C 2.0

The max int is 32767

Max int plus 1 is -32768

The max unsigned int is 65535

Max unsigned int plus 1 is 0

测试二:32位电脑运行系统Windows 3.2

GCC 4.4.1

无法运行,系统不支持。

Turbo C 2.0

The max int is 32767

Max int plus 1 is -32768

The max unsigned int is 65535

Max unsigned int plus 1 is 0

目前来看,在硬件相同,OS不同前提下,同一编译器编译结果不变。暂时可认为INT取值范围与OS无关运行系统。

测试三:286电脑(硬件16位)

因无硬件,故此项测试无法进行。当然,就算有16位电脑,也不见得能做出测试。因为OS必然不可能是32位,自然GCC还是无法运行。有一个硬性的规定,即OS位宽不能大于电脑位宽,而编译器(或软件)位宽不能大于OS位宽(这么说可能不大合适,但意思应该表达出来了)。

虽然无法做出测试,但是我们也还是可以就上面测试一、二所得结果推导出来。首先,在32位系统下,虽然运行了16位的TC2.0,但是得出的结果却 不是32位;运行32位的GCC,结果是32位。这说明整个软硬件是可以得出32位INT的,但TC却没有得出。TC没有因为电脑位宽而改变它的想法。它 就只认一点,不管在什么电脑上,也不管在什么OS上,只要我能运行,我的INT就是16位的。老子就这么拧,看你拿我怎么着。

似乎照这么看,INT取值范围与电脑硬件位宽也无关。

那么,还剩下的就只有编译器了。真的跟它有关吗?好的,我们再来试试。这一次,我们来改改编译器看看。

测试四:32位电脑运行系统Windows XP(因为要对两个编译器作对比。必须要都能运行,故选此软硬件系统)

GCC 4.4.1    C头文件limits.h整数部分定义

/* Maximum and minimum values for ints. */

#define INT_MAX             127               //原来2147483647

#define INT_MIN              (-INT_MAX-1)

#define UINT_MAX      0xffff

TC 2.0   C头文件limits.h整数部分定义

#define INT_MAX                    127           //原来32767(0x7FFF)

#define INT_MIN                     ((int)0x8000)

#define UINT_MAX           255

运行结果

GCC 4.4.1

The max int is 127

Max int plus 1 is 128

The max unsigned int is 65535

Max unsigned int plus 1 is 65536

Turbo C 2.0

The max int is 127

Max int plus 1 is 128

The max unsigned int is 255

Max unsigned int plus 1 is 256

得出结果有点出乎意料之外,改了头文件后,运行结果显示的INT_MAX正好是自己改的数字,但是INT_MAX+1却没有溢出。依然是127+1(128)而不是-128。同样,上面把INT_MAX分别改为:

GCC 4.4.1    C头文件limits.h整数部分定义

/* Maximum and minimum values for ints. */

#define INT_MAX             9223372036854775807  

TC 2.0   C头文件limits.h整数部分定义

#define INT_MAX                    2147483647

GCC 4.4.1

The max int is -1

Turbo C 2.0

The max int is -1

发现如果所设数值比默认值大但小于一个等级,如GCC中数值在LONG INT(比INT高一个等级)范围内,基本上得出结果有点随机。如超出一个等级,则显示-1。具体原因我目前还不大清楚,估计应该是编译器中还有什么文件 也要相应修改才行。之所以产生这种结果,个人感觉也应该跟堆栈有关。还有为什么INT_MAX设为127,但加1后没溢出,应该也是如此。这里我就不赘述 了。详见《C Primer Plus (第五版)》 中文版 第75页 例4.12及其解析。

小结:首先请了解

1、关于INT取值范围首先是一个标准问题,就拿C来说,INT的取值范围主要由ANSI C规定。这一点是不容置疑的。目前ANSI C规定INT最小不小于16位。

2、关于位宽问题有点像现在面向对像编程里面的继承一样。电脑硬件位宽就是父构件,操作系统OS就是其子构件,编译器又是OS的子构件。子构件可以继承父构件的位宽,但是跟派生不一样,子构件无法超出父构件的位宽。即子构件真包含于父构件。

于是乎得出如此结论:

INT的取值范围取决于编译器。但前提是不超过OS及电脑位宽。

编译器因为其制作的历史条件及环境因素,位宽肯定不会超过当时的操作系统和电脑硬件,但不一定会等于当时的OS及电脑。像TC就是一个很好的例子。 当有一个位宽更大的操作系统运行以前的老编译器时(能运行的话),那么所得结果还是以老编译器为准。因此,如果说INT取值范围由操作系统或由电脑决定, 虽不能说这种说法错误,但仍然有些不妥。

别话:

   

为了解释起来方便,在很多地方用了“位宽”一词,可能在某些地方不太合适,这里仅仅是为了INT取值范围而用。相信其中意思大家应该理解。

    由于近期找工作,还要不断学习提升自己,再加上电脑实在太慢,搞个虚拟机要半天,还有几个编译器间来回调试。所以时间安排上有点紧,无法进行更精细的测 试。再加上自己经验有限,有些地方难免会有此疏漏及错误,望各位大虾不吝赐教。至于某些朋友特别是那些复制粘贴党硬是要拿个什么破书(或是很好的很著名的 破书)来说“书上是这么说的”就免了。我只相信实验,相信事实。对于读死书我是很鄙视的,谁说专家就不会错了。这年头连牛顿的万有引力都不能说放之万物皆 准(至少对于相对论是如此),更何况对于程序语言这种相对变化频繁的东东。真理永远是有时效的,请学会怀疑权威,这样才会让你进步。

阅读(1122) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~