原码、反码、补码(1)

计算机中的整数共有3种二进制的表示方法:原码、反码、补码。下面是对这3种表示方法的介绍:

1.计算机中的整数共有3种二进制表示方法,即:原码、反码、补码(内存中存的就是补码)
2.三种方法均有符号位(即最左边的第一个数字)和数值位两部分,符号位用“0”表示“正”,“1”表示“负”
3.正数的原、反、补码都相同;而负数则非也。

代码示例如下:

//正数的原码、反码、补码和负数的原码、反码、补码

int main()
{
	int a = 20;//正数的
	//int-->4byte-->32bit;
	//00000000000000000000000000010100-->20的原码
	//00000000000000000000000000010100-->20的反码
	//00000000000000000000000000010100-->20的补码
	int b = -10;//负数的
	//10000000000000000000000000001010-->-10的原码
	//11111111111111111111111111110101-->-10的反码(将原码中的“1”变成“0”,“0”变成“1”即可得到负数的反码)
	//11111111111111111111111111110110-->-10的补码(将反码加“1”即可得到负数的补码)
	//1111(f)1111(f)1111(f)1111(f)1111(f)1111(f)1111(f)0110(1*2^2+1*2^1=6)(写成16进制)
	//即f f   f f   f f   f 6(倒置存放:f 6   f f   f f   f f)
	return 0;
}

4.在计算机中,数字一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理
5.同时,加法和减法也可以统一处理(CPU只有加法器),此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路
6.内存中存放的是补码,整型表达式计算使用的是内存中的补码来计算的
7.打印和我们看到的都是原码

代码示例如下:

//int c = 1 - 1;
//1-1会转化成1+(-1)计算
// 
//转换成原码计算
//00000000000000000000000000000001-->1的原码
//10000000000000000000000000000001-->-1的原码
//10000000000000000000000000000010-->相加之后---->-2      error

//转换成补码计算
//  00000000000000000000000000000001-->1的补码
//  11111111111111111111111111111111-->-1的补码
//100000000000000000000000000000000-->进一以后最左边的那个“1”没用了,会丢失,最后会得到如下所示补码
//  00000000000000000000000000000000-->0=1-1       right

注意:

(1)原码到补码--->1种方式(即为上面代码通过原码求补码的方法)
(2)补码到原码--->2种方式---->1.先”减一“(得反码),再取反(原码)   2.先取反,再“加一”(注意是加一)

8.大小端

(1)出现原因:一个数值超过一个字节了,要存储到内存中就有顺序问题
(2)大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中;
(3)小端(存储)模式,是指数据的高位保存在内存的高地址中,而数据的低位保存在内存的低地址中;(VS、x86)
(4)小端字节序存储:把一个数值的低位字节的内容,存放在低地址处,高位字节的内容,存放在高地址处
(5)大端字节序存储:把一个数值的低位字节的内容,存放在高地址处,高位字节的内容,存放在低地址处

解释如图:

设计一个程序来判断当前机器的字节序: 

代码如下: 

//在main函数中实现
#include <stdio.h>
int main()
{
	int a = 1;
	char* p = (char*)&a;
	if (*p == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}


//调用函数简化版
#include <stdio.h>
int check_sys()
{
	int a = 1;
	return (*(char*)&a == 1);//不要忘记了解引用
}
int main()
{
	if (check_sys() == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

练习1:

结果如下:

 

解释如下: 

//整型提升的时候要看有无符号
//有符号--->高位(即符号位)是什么就补什么
//无符号--->补0

#include <stdio.h>
int main()
{
	char a = -1;//-1截断以后存到a中
	//10000000000000000000000000000001-->-1的原码(-1是整数,int类型有32个bit)
	//11111111111111111111111111111110-->-1的反码
	//11111111111111111111111111111111-->-1的补码(a是char类型的变量,占一个字节,只能存8个比特位,所以只能存低地址的8个比特位,如下(被截断))
	//11111111--->最高位是符号位
	//a--->整型提升以后如下
	//11111111111111111111111111111111--->补码
	//10000000000000000000000000000001--->原码-------->-1

	signed char b = -1;//(同上)
	//10000000000000000000000000000001-->-1的原码(-1是整数,int类型有32个bit)
	//11111111111111111111111111111110-->-1的反码
	//11111111111111111111111111111111-->-1的补码(a是char类型的变量,占一个字节,只能存8个比特位,所以只能存低的8个比特位,如下(被截断))
	//有符号--->最高位是符号位
	//11111111--->最高位是符号位
	//a--->整型提升以后如下
	//11111111111111111111111111111111--->补码
	//10000000000000000000000000000001--->原码-------->-1

	unsigned char c = -1;
	//11111111111111111111111111111111-->-1的补码
	//11111111
	//无符号--->不会将最高位看作符号位
	//c--->整型提升以后如下
	//00000000000000000000000011111111(高位补0)
	//提升以后,最高位是0,表明是正数,故
	//原码,反码,补码都一样
	//所以打印出来是255
	printf("a=%d,b=%d,c=%d", a, b, c);//%d--->打印整型
	return 0;
}

练习2:

结果如下:

 

 解释如下:

//下面程序输出什么
#include <stdio.h>
int main()
{
	char a = -128;
	//10000000000000000000000010000000--->-128的原码
	//11111111111111111111111101111111--->-128的反码
	//11111111111111111111111110000000--->-128的补码
	//10000000--->整型提升
	//11111111111111111111111110000000---("%u\n",a)
	printf("%u\n", a);//%u打印无符号整型,认为内存中存放的补码是一个无符号数;%d打印有符号整型,认为内存中存放的补码是一个有符号数

	return 0;
}

若将a改为128也是一样的答案:

解释如下:

#include <stdio.h>
int main()
{
	char a = 128;//即使成了128,答案还是不变
	//00000000000000000000000010000000--->-128的原码
	//01111111111111111111111101111111--->-128的反码
	//01111111111111111111111110000000--->-128的补码
	//10000000--->整型提升
	//11111111111111111111111110000000---("%u\n",a)
	printf("%u\n", a);//%u打印无符号整型,认为内存中存放的补码是一个无符号数;%d打印有符号整型,认为内存中存放的补码是一个有符号数

	return 0;
}

练习3:

结果如下:

 解释如下:

#include <stdio.h>
int main()
{
	int i = -20;
	//10000000000000000000000000010100--->-20的原码
	//11111111111111111111111111101011--->-20的反码
	//11111111111111111111111111101100--->-20的补码
	unsigned int j = 10;
	//00000000000000000000000000001010--->10的原码(补码)
	printf("%d\n", i + j);
	//补码相加
	//11111111111111111111111111101100--->-20的补码
	//00000000000000000000000000001010--->10的原码(补码)
	//11111111111111111111111111110110--->相加
	//11111111111111111111111111110101--->反码
	//10000000000000000000000000001010--->原码---->-10
	return 0;
}

 

 


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值