我们经常要接触的整型数的范围,比如signed char的范围是-128~127,signed short的范围是-32768~32767。
这里将要告诉你,是怎么计算出来的。
拿signed char来说明一下:
因为是有符号的整数,最高位为符号位
1.对于正数,最大值的二进制表示为: 0111 1111
计算出它的值: (1 << 7) - 1 = 127, 没有问题
2.对于负数
最小值的二进制表示为: 1111 1111
计算出它的值: -127, 有问题,怎么不是-128?
现在先告诉大家,后面详细说明: 最小的负数表示不是 【1111 1111】 而是【1000 0000】,而计算机规定signed char 情况下【1000 0000】的值为-128;
-127 也不是用【1111 1111】原码表示, 而是用其补码【1000 0001】表示的。
要弄清楚这个问题, 就要引入计算机的字节编码的概念, 原码,反码和补码的概念。
一开始的时候,计算机只支持原码的。
原码是指一个二进制数左边加上符号位后所得到的码,且当二进制数大于0时,符号位为0;二进制数小于0时,符号位为1。
但是存在问题, 举例说明:
1 + 2= 3
(0000 0001)原 + (0000 0010)原 = (0000 0011)原 => 3
1 - 1 = 0
(0000 0001)原 + ( 1000 0001)原 = (1000 0010)原 => -2
1减去1的值应该等于0 的, 但是转换成1 和 -1的原码加法运算的值是-2,明显错误。
所以,计算科学中就引入了反码和补码的概念, 非负数用原码表示, 负数用补码表示。现在的计算机99.99999999999999%是补码表示。
反码: 正数和0的反码是其本身;负数保持符号位不变,其它各位求反(1变0, 0变1)
补码: 整数和0的补码是其本身, 负数的补码是其原码的反码,再加上1得到的数值。
补码与补码 或者 补码和原码,看作是补码,得到原码的过程求反再加1
现在再看一下 1减去1的例子:
(0000 0001)原 + (1111 1111)补 = (0000 0000)补 => 0
值是0, 正确了。
但是有一个特殊的补码 【1000 0000】,计算机规定其值为-128,因为计算机中0是看作正整数的,其反、补码都一样,故【1000 0000】没有其它成员使用。
此处是1个字节的有符号整数, 其它的如short, int, long long类型,计算机也是相似的处理, 把符号位为1,其他位为0的看作是最小值(最大值加1的负数)
============================
通过以上的学习,现在可以轻松计算出,8位,16位, 32位, 64位有符号整数的范围了。
我用C语言简单实现
#include <stdio.h>
#include <stdint.h>
#define MAX_INT8 0x7f
#define MIN_INT8 ((int8_t)0x80)
#define MAX_UINT8 0xff
#define MAX_INT16 0x7fff
#define MIN_INT16 ((int16_t)0x8000)
#define MAX_UINT16 0xffff
#define MAX_INT32 0x7fffffff
#define MIN_INT32 ((int32_t)0x80000000)
#define MAX_UINT32 0xffffffff
#define MAX_INT64 0x7fffffffffffffff
#define MIN_INT64 ((int64_t)0x8000000000000000)
#define MAX_UINT64 0xffffffffffffffff
int main(int argc, char *argv[])
{
printf("max_int8 = %d\n", MAX_INT8);
printf("min_int8 = %d\n", MIN_INT8);
printf("max_uint8 = %u\n", MAX_UINT8);
printf("max_int16 = %d\n", MAX_INT16);
printf("min_int16 = %d\n", MIN_INT16);
printf("max_uint16 = %u\n", MAX_UINT16);
printf("max_int32 = %d\n", MAX_INT32);
printf("min_int32 = %d\n", MIN_INT32);
printf("max_uint32 = %u\n", MAX_UINT32);
printf("max_int64 = %lld\n", MAX_INT64);
printf("min_int64 = %lld\n", MIN_INT64);
printf("min_uint64 = %llu\n", MAX_UINT64);
return 0;
}
运行结果:
max_int8 = 127
min_int8 = -128
max_uint8 = 255
max_int16 = 32767
min_int16 = -32768
max_uint16 = 65535
max_int32 = 2147483647
min_int32 = -2147483648
max_uint32 = 4294967295
max_int64 = 9223372036854775807
min_int64 = -9223372036854775808
min_uint64 = 18446744073709551615