#include <stdio.h>
int main() {
char a = 1;
char b = 127;
char c = a + b;
printf("%d\n", c);
return 0;
}
打印的结果是-128,具体的计算过程如下:
类型提升和相加的操作:
1、变量初始化:char a = 1;初始化为1,char b = 127;‘初始化为127;
2、类型提升:在表达式a+b中,char的 类型会被提升为int类型,因此a和b在相加之前被提升为int类型,说是提升的原因是char的取值范围是-128~127而int的取值范围是-32768~32767(另外一种的char范围0-255;int范围 -2147483648~ 2147483647在这里不讨论);
3、相加的操作: a+b = 128,128的结果要存到char类型的变量c中,然而char的范围是-128-127,这里的128显然不在这个范围中,这就发生了溢出,溢出的计算结果是-128。下面来看一下具体的溢出计算过程。
在这里需要了解计算机是如何进行计算的。
在计算机二进制中我们可以使用三种方式来表示一个数:原码、反码、补码。
原码的表示:在原码中最高位存放符号位,0为正数,1为负数,因此这里a的原码表示为0000 0001,b的原码表示为01111111;
反码的表示:正数的反码是其本身,负数的反码在其符号位不变的基础上其余各位取反比如:
补码的表示:正数的补码是其本身,负数的补码在其符号位不变的基础上其余各位取反,最后一位+1,例如:
原数 | 原码 | 反码 | 补码 |
1 | 00000001 | 00000001 | 00000001 |
-1 | 10000001 | 11111110 | 11111111 |
知道了原码、补码、反码之后我们可以看一下为何需要引入原码、补码、反码。
8位原码计算1-1:
1-1 = 1 + (-1) = (00000001) + (10000001) = 10000010 = -2,这么计算的结果显然是有问题
8位反码计算1-1:
1-1 = 1 + (-1) = (00000001) + (11111110) = 11111111,反码11111111的原码是10000000,按道理来说10000000的十进制的值为-0(实际不是的哈,是-128),看起来怪怪的哈,根据原码的定义我们可以知道0的原码还可以表示为00000000,这样一个0就有了两个编码,这种的不是我们希望的,我们希望最好一个数字只有一个编码来表示
8位补码计算1-1:
1-1 = 1 + (-1) = (00000001) + (11111111) = 0000 0000 这样以前的-0问题就么得了。
了解了原码、反码、补码的计算之后,我们就可以来计算一下a+b了。
a 0000 0001(补码)
+
b 0111 1111(补码)
= 1000 0000
char的类型是8位的,它的最高位规定为符号位,0表示正数,1表示负数,这里计算结果的最高位是1,按照规定它是一个负数
这里我们将二进制补码1000 0000转换为反码
1000 0000
- 1
= 0111 1111
再将反码转换为原码
0111 1111
(取反)
1000 0000
换了一圈又回去了哈,所以可以确认它是补码的极限值了,这样我们就可以确认它的值是-128了