前言:
原码、反码、补码的知识点在操作符篇中讲过,但是由于写的太分散,在这里重新整理一遍,以方便查阅。
1、计算机在任何情况下只能识别二进制
2、计算机在底层存储数据的时候,一律存储的是二进制补码的形式
3、二进制的原码、反码、补码
注释:
一个二进制数是由数值位和符号位组成,在符号位的0表示该数为正数,1表示该数为负数。
一、原码、反码、补码
原码:原码对应的十进制数为计算机输出结果
补码:数据都是以二进制补码的形式存储的
1、 正数(正数的原码、反码、补码不变)
整数15、在C语言中可以存放到int类型的变量中,int类型时4个字节,32个比特位。
00000000 00000000 00000000 00001111 ——15的原码
00000000 00000000 00000000 00001111 ——15的反码
00000000 00000000 00000000 00001111 ——15的补码
2、负数
负数的反码是符号位不变,其余取反
负数的补码是在反码的基础上加1
以-15为例
10000000 00000000 00000000 00001111 —— -15的原码
11111111 11111111 11111111 11110000 —— -15的反码
11111111 11111111 11111111 11110001 —— -15的补码
二、整型提升
整型提升:
对于在内存中所占字节小于int的数据,例如 char,short类型的数据,在进行加减时会进行隐形转换,转换成int类型的数据后再进行加减
整型提升的意义:
表达式的整形运算要在CPU的相应运算期间内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPU是难以直接实现两个8比特字节直接相加运算。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
实例:
#include<stdio.h>
{
char a = 5;
//00000000 00000000 00000000 00000101 ——5的补码,要存进a中,要发生截断
//00000101 —— 发生截断,a中存的
char b = 126;
//00000000 00000000 00000000 01111110 ——126的补码,要存进b中,要发生截断
//01111110 —— 发生截断,b中存的
char c = a + b;
//00000101 —— a中存的
//01111110 —— b中存的
整型提升a,b
//00000000 00000000 00000000 00000101 ——a
//00000000 00000000 00000000 01111110 ——b
//00000000 00000000 00000000 10000011 ——(a+b)
//10000011 ——c 发生截断
printf("%d\n",c);//在这里也要发生整型提升,%d打印的是十进制有符号整数
//11111111 11111111 11111111 10000011 ——c的补码
//11111111 11111111 11111111 10000010 ——c的反码
//10000000 00000000 00000000 01111101 ——c的原码
return 0;
}
结果是:-125
注释:
1、整型提升前面添加的是1还是0由符号位说了算,
2、发生截断后的二进制数首位是符号位,
例如:
a+b的二进制数发生截断是 10000011,首位是1,在整型提升是32为二进制数,首位为1.
整型提升后为11111111 11111111 11111111 10000011
补充:无符号整型提升,高位补0。
三、 补码运算原理
上述的代码中的a=5,b=126,c=-125原因是什么
在这里简单说一下补码运算的原理:这里以signed char 类型为例 ,取值范围为 -128~127
在 signed char类型中正数为0~127,在上述的轮回中,超过127后循环会到达-128,依次向下循环。所以a+b=-125。
补码的运算:
在计算机系统中,数据一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时、加法和减法也可以统一处理(cpu只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
int main()
{
int c = 1 - 1;
//在这里1-1;计算机理解为 1+(-1);
//00000000 00000000 00000000 00000001 —— 1的补码
//11111111 11111111 11111111 11111111 —— -1的补码
//00000000 00000000 00000000 00000000 —— (1+(-1))的补码,在这里由第一位1+1得2向
//前进一位,出现33位,从低位到高位只读取32位。
}
原码到补码有一种方式
首先原码取反、再+1得到补码
-1
10000000 00000000 00000000 00000001 原码
11111111 11111111 11111111 11111110 反码
11111111 11111111 11111111 11111111 补码
补码到原码 有两种方式
1、首先补码-1、再取反得到原码
2、首先补码取反、再+1得到原码
以-1为例:
11111111 11111111 11111111 11111111 补码
10000000 00000000 00000000 00000000
10000000 00000000 00000000 00000001 原码