
1.14 取值范围

视频讲解
前面介绍了数据类型,还讲了如何获得数据类型的尺寸,无非就是为了求得它的取值范围。那取值范围意味着什么呢?取值范围就意味着这个变量可以存放的最大值和最小值分别是多少。
那这个值如何计算呢?要从二进制的单位——比特(bit)说起。人们总是说CPU非常“笨”,是因为它只认识二进制,比特是CPU能读懂的最小单位。
而我们人类则相反,不喜欢用比特来计算,一般说内存机构的最小寻址单位是字节(Byte)而不是比特。字节与比特是什么关系呢?1字节存放8比特。
每个比特只能存放二进制的0或1,那么1字节最大可以存放的数是多少?因为是二进制,所以最大的数无非就是:

如果用习惯的十进制数表示的话,是多少呢?取值范围见表1-2。
表1-2 取值范围

1字节等于8比特,用二进制表示是11111111,而对应的十进制数就是255,值是一样的,只是表示的方式不同而已。255就是1字节可以表示的最大值。
1.12节中求得sizeof(int)的值是4字节,也就是一个整型变量在这个虚拟机系统中占4字节的存储空间。4字节就是32比特,用二进制表示最大值就是32个1,用十进制表示是多少呢?我们总不能从0一直数到32个1吧?当然不,学习数学就是让我们学会利用一些规律,来提高工作效率的。
观察表1.2:二进制11对应十进制的值相当于2的2次方减1(22-1=3);二进制111对应十进制的值相当于2的3次方减1(23-1=7);二进制1111对应十进制的值相当于2的4次方减1(24-1=15)……也就是说有多少比特,就是先求2的多少次方,再减1,对应的就是转换为十进制数的值。所以,二进制32个1可以表示的最大值应该就是2的32次方减1,即232-1=4294967295。
【扩展阅读】这里只是告诉大家一个小技巧,有关进制转换的更多技巧并不在本书的讨论范围之内,感兴趣的读者可以访问http://bbs.fishc.com/thread-67123-1-1.html(注:此网址在2018年8月时可正确访问)或扫描图1-15所示二维码进行查阅。

图1-15 进制转换
pow函数用于进行求幂运算,只要将底数和指数作为参数传递给它,就会返回对应的结果。比如,pow(2, 3)返回的是8,pow(2, 5)返回的是32。现在利用pow函数,算一算int可以存放的最大值是多少。

注意:
pow函数是属于math库的函数,所以编译的时候需要加上-lm命令。
程序实现如下:

打印出了结果“result=2147483647”,但却多了两行内容。编译后如果出现一些奇怪的内容,那就说明代码有问题,这是GCC编译器给我们的提醒:test7.c:6: warning:overflow in implicit constant conversion,意思是代码的第6行有个警告。一般编译结果有问题就可能出现警告(warning)或错误(error):警告表示编译器怀疑你的代码可能有问题,但可以通过编译并生成可执行文件;而错误则表示代码存在语法错误,无法通过编译。这里是一个警告,内容是:常量转换溢出。
2的32次方减1的值应该等于4294967295,而编译器显示的却是2147483647,怪不得会有“警告”。这是因为在默认情况下,int是signed类型的,即带符号位的整型。在存放整型的存储单元中,左边第一位不用来存放数值,而是表示符号位。如果该位为0,表示该整数是一个正数;如果该位为1,表示该整数是一个负数。所以,如果想要将整型的32比特全部用来存放数据的值,那必须用unsigned int来声明变量,代码修改为:

程序实现如下:

那么如果是signed int类型,可以存放的最大值是多少呢?
分析:一个32比特的整型变量,除去左边第一位是符号位,剩下表示值的只有31比特。因此,int类型最大能够存放的整数应该是2的31次方减1。
代码如下:

程序实现如下:

无符号数的最小值肯定是0,因为它没有负数。但对于有符号数来说,它的最小值应该是多少呢?
要搞清楚这个问题,就需要先弄清楚计算机是如何存储负数的。事实上,计算机是用补码的形式来存放整数的值(包括正整数和负整数)。正数的补码是该数的二进制形式。负数的补码需要通过以下几步获得:先取得该数的绝对值的二进制形式;再按位取反;最后加1。
举个例子,对于1字节单元来说,7的补码是这么存放的:

而-7则需要先获得7的二进制形式:

然后按位取反(就是除了符号位,其他位中0变成1,1变成0):

再加1,得到-7的补码形式:

使用补码来存放整数有一些特征:当符号位为0的时候,后边的1越多,整数的值就越大;而当符号位为1的时候,后边的0越多,整数的值就越小,如图1-16所示。
对于1字节来说,最小值是-128,而最大值却是127,这是为什么呢?这是因为从正数中分割了一个位置给一个特殊的数,那就是0。
【扩展阅读】使用补码的好处请访问http://bbs.fishc.com/thread-67124-1-1.html或扫描图1-17所示二维码进行查阅。

图1-16 补码

图1-17 使用补码的好处
表1-3是截至目前我们接触过的数据类型的取值范围。
表1-3 取值范围

关于浮点数的存放形式和取值范围本书不要求掌握,不过有些读者朋友会感兴趣,所以这里准备了两篇扩展阅读,感兴趣的读者可以自己参考学习。
【扩展阅读】定点数:用二进制表示小数请访问http://bbs.fishc.com/thread-67211-1-1.html或扫描图1-18所示二维码进行查阅。

图1-18 定点数:用二进制表示小数
【扩展阅读】浮点数:表示更大范围的小数请访问http://bbs.fishc.com/thread-67214-1-1.html或扫描图1-19所示二维码进行查阅。

图1-19 浮点数:表示更大范围的小数