整型在内存中的存储 原反补与大小端

作者的话

本文介绍整型在计算机中的以什么样的方式存储,包括“三码”相关知识、截断与提升相关知识、大小端存储相关知识~


整型在内存的存储

计算机是一种电器,而电荷只有正电荷负电荷之分,因此,任何数据在计算机中只能以二进制存储,即0和1的组合

而在计算机中,整型有三种二进制表示方式,这三种存储方式的名字分别是原码、反码、补码。

三种方式均分为符号位和数值位,从左数第一位是符号位其余位数值位,像这样
在这里插入图片描述
上图是一个32位整型的例子,符号位是1,则这个数是负数;符号位是0,则这个数是正数

unsigned与signed

然而,并不是所有的整型都有符号位。

unsigned开头的数据类型就是无符号位类型,比如unsigned int、unsigned short int、unsigned char,这三种。

对于这三种类型来说,他们的符号位和数值位一样,都代表着数据的大小,因此,这三种数据类型也没有正负之分,他们只可能是正数

比如说:signed char的范围是-128 ~ 127,而unsigned char,因为多了一位做数值位,所以数据的上限要翻一倍,故unsigned char的取值范围是0 ~ 255。

原码反码与补码

刚才我们说到,整型在计算机中有三种二进制存储形式,分别是原码,反码,补码

对于正数、unsigned型的数来说,原码反码补码完全相同,即这三者的书写方式一模一样。

但对于负数来说,这三者各不相同,转换规则如下:

原码符号位不变,其他位取反,就成了反码。

反码+1,即是补码。

例如:

-119的原码:10000000000000000000000001110111

-119的反码:01111111111111111111111111111001000

-119的补码:01111111111111111111111111111001001

由此可见:

  • 原码就是数据按照大小翻译成二进制,再看类型和正负决定符号位。
  • 原码与反码的转换过程相同,即原码取反+1后是补码,补码取反+1后又变成了原码。

计算机内的存储

虽然二进制有三种表示方式,但在计算机中,总是以补码的方式保存。

原因如下:

  1. CPU只有加法器,用补码存储可以无视符号位与数值位的区别,把他们两个放在一起计算。
  2. 刚才说原码和补码的转换方式相同,这样可以节省硬件电路的复杂度。

计算机存储过程

所谓过程,就是如何把这个数据放进计算机里面。

如果每种整型类型对应放置每种整型数据,那自然没什么好说的。

但是如果类型不同,就会发生截断

截断:

超出某类型范围的数据放入该类型空间时,只保留一部分,像这样:

signed char的范围是-128~127。

如果我偏要把128放进去,然后打印,会发生什么?

打印的结果居然是-128 其原因就是在放入数据和取出数据的时候分别发生了截断和提升。

详解:

128的原码:00000000000000000000000010000000

128的补码:011111111111111111111111111110000000

因为a是1个字节,一个字节占8个bit位,所以从低位截出8位来。

截完以后a的内部:10000000

这就是截断,记住从操作系统从低位开始截,而且截的是补码。

a提升后的补码:11111111111111111111111110000000

a提升后的原码:10000000000000000000010000000

这一串翻译成十进制就是-128

整型如何提升

整型提升,用一句话说就是占用空间小于4个字节的数据类型,在使用时要先转换成至少为4个字节的int类型后,才能使用。

至于提升的方法,一共有两种,对于有符号数(signed)来说,按符号位提升;对于无符号数(unsigned)来说,无脑补0,像这样:

char a=0b10000000;
unsigned char b=0b11110000;

补完以后:

a:11111111111111111111111110000000

b:00000000000000000000000011110000

大小端存储

  • 大端字节序存储模式,简称大端模式,是指数据的低位字节保存在内存的高位处
  • 小端字节序存储模式,简称小端模式,是指数据的低位字节保存在内存的低处

下面演示一个小端字节序的存储,像这样:

在这里插入图片描述

上图可以看到,a的低位地址(0x00EFFB94),存储的是数据的低位字节;a的高位地址(0x00EFFB97),存储的是数据的高位字节。

注意:一个内存单元的大小是一个字节,因此,大小端存储的单位也是一个字节。

存在意义

我们知道,一个内存单元的大小是1个字节,但除了char类型,其他数据的占用空间大小都在1个字节以上,想要把一个数据的每个字节都放在一起,排列的顺序自然就成了一个问题。

历史遗留:

据说灵感来自格列佛游记,在格列佛游记中有一个小人国,有一个大人国,有一天大人国送了小人国一个鸡蛋,小人国的国王就在想,是从鸡蛋大的那一头开始剥,还是从小的那一头开始呢?
于是就有了大小端的说法,不同的模式没有优劣之分,只是选择不同。

如何分辨

当前我们常用的x86机器,采用的是小端存储模式,那么:

如何设计一个程序,可视化地判断当前环境是大端存储还是小端存储呢?

我们知道,计算机读取数据总是从低位开始读取,那么我们只需要令一个占用空间大于1个字节的变量存储一个小于1个字节的数据,然后利用指针类型的特性读取这一个字节就可以了,像这样:

int main()
{
	short a = 0x0001;	
    char* p = (char*)&a;

	printf("%d", *p);

	return 0;
}

short型数据占两个字节,我们以char类型的指针读取其中的低位第一个字节,查看打印的数字是0还是1即可。

效果图:
在这里插入图片描述

可以看到,打印结果是1,符合我当前的小端机器。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵千阳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值