前言:我们知道一个变量的创建是要在内存中开辟空间的,而空间的大小是根据不同类型而决定的,那么数据在所申请开辟的内存中是如何存储的呢?这里我们就来讨论整型在内存中是如何存储的。
原码,反码,补码
首先,我们需要知道在计算机中整数有3种2进制表示方法,即原码
反码
补码
。这3种表示方法均分为符号位和数值位两部分,符号位用0来表示“正”,用1来表示“负”,而数值位的表示方式正负数则略有区别。
整型在内存中占4个字节,1个字节(byte)就是8个比特位(bit),那么一个整型就占据了32个比特位,所以它能由32位二进制数表示。而开头的比特位就是符号位,余下31个比特位则是数值位。
正负数的原反补码表示形式
正数的原反补码形式都相同。
负数的原反补码形式各不相同
原码:直接将数值按照正负数的形式翻译成二进制就可以得到原码。
反码:原码的符号位不变,其他位依次按位取反就可以得到反码
补码:在反码的基础上加1得到补码
例子如下:
int a = 10;
// 00000000 00000000 00000000 00001010 - 原码
// 00000000 00000000 00000000 00001010 - 反码
// 00000000 00000000 00000000 00001010 - 补码
int b = -10;
// 10000000 00000000 00000000 00001010 - 原码
// 11111111 11111111 11111111 11110101 - 反码 - 符号位不变,其他位按位取反
// 11111111 11111111 11111111 11110110 - 补码 - 在反码的基础上加1
需要注意的是:整型在内存中是以补码形式存储的,而输出则是以原码形式输出。
整型提升
下面让我们看这段代码:
char a = -1;
// 变量a的类型是char,在内存中占一个字节,而-1是个整型值,在内存中占4个字节,那么-1该如何存储呢?
signed char b = -1;
// 有符号呢?
unsigned char c = -1;
// 无符号呢?
printf("a=%d,b=%d,c=%d", a, b, c);
大家觉得答案分别是多少呢?
运行后答案如下:
为什么输出结果是这样的呢?解析如下:
char a = -1;
// 首先将-1的补码写出来
// 10000000 00000000 00000000 00000001 -1的原码
// 11111111 11111111 11111111 11111110 -1的反码
// 11111111 11111111 11111111 11111111 -1的补码
// char在内存中占1个字节,即8个比特位,所以发生截断,取-1补码的后8位数 11111111
// 11111111放入c中,但我们打印的是有符号整型(%d),所以需要32个比特位,即需补上24个比特位
// 整型提升,符号位上是几,咱们就补几,11111111的符号位上是1,所以我们补1
// 11111111 11111111 11111111 11111111 补后的补码
// 11111111 11111111 11111111 11111110 反码
// 10000000 00000000 00000000 00000001 原码
// 读原码为-1,则输入-1
signed char b = -1;
//同上
unsigned char c = -1;
// 首先将-1的补码写出来
// 10000000 00000000 00000000 00000001 -1的原码
// 11111111 11111111 11111111 11111110 -1的反码
// 11111111 11111111 11111111 11111111 -1的补码
// char在内存中占1个字节,即8个比特位,所以发生截断,取-1补码的后8位数 11111111
// 11111111放入c中,但我们打印的是有符号整型(%d),所以需要32个比特位,即需补上24个比特位
// 整型提升,无符号位补符号位是没有意义的,所以直接补0
// 00000000 00000000 00000000 11111111 补后的补码 符号位为0,原反补码相同
// 00000000 00000000 00000000 11111111 反码
// 00000000 00000000 00000000 11111111 原码
// 读原码为255,则输出255