2024年C C++最全深入理解《有理数》在电脑中是怎么存储的_有理数的虚拟存储结构,花三分钟看完这篇文章你就懂了

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

博主正在朝着看代码是内存的道路前进!

  • 从我们初识C语言开始,我们前几课就已经学了各种各样的数据类型。但是我们可能只是了解了这些数据类型怎么去使用,比如这里,int a = 10;我们定义了一个整型变量a,它的值是10。但是我们并不知道这个数字10怎么在内存中存储的。
    在这里插入图片描述

🌳 数据在内存中以什么形式存储

  • 首先,要设置一个问题,引出接下来要讲的内容。
    以32位机器为例
  • 1.我们定义了一个整型变量a。int a = 10;那么这个10进制的数字10,是怎么在计算机中存储的呢?
  • 2.如果是以二进制的方式存储,那么它是怎么显示的?
  • 大多数计算机使用一个字节(1byte=8bit),作为最小的可寻址的存储器单位,而不是在存储器中访问单独的位(bit)。
  • 接下来,我们讲述编译器和运行时系统是如何将存储器空间划分为更可管理的单元。

🌳十六进制表示法

  • 一个字节由八个位组成。在二进制表示法中,他的取值范围是00000000~11111111(也就是十进制的0 到 255)
  • 由于二进制表示法太冗长,十进制表示法与位模式的互相转化又很麻烦。
  • 所以诞生了以16进制(HEX)来表示位模式在内存中表示.
  • 它是用0~9以及用字符A到F来表示16个值,也就是表示0到15这16个数字。
  • 在C语言中。以0x或者0X开头的数字就是16进制。字母A到F即可大写也可以小写。
二进制如何转换成16进制

在这里插入图片描述

  • 每四个二进制位可以转换成一个16进制的数字。
  • 例如:给你一个173A4C。如何转换成二进制?
  • 如下所示

在这里插入图片描述这样我们就得到了32位的二进制表示00010111001110101001100

🌳这个16进制位的数字如何在内存中表示?

大、小端字节序
  • 假设让数字0x11223344放在内存中 ,那他是如何表示的呢?
  • 实际内存中存的就是是它的二进制序列,只是内存中的表示一般是16进制。
  • 我们打开vs,切换到内存。
#include<stdio.h>
int main()
{
	int a = 0x11223344;
	return 0;
}

  • 我们以这段代码为例。我们进入调试。使用&操作符拿到a的地址。然后在内存中的该地址上的数是如何表示。
    在这里插入图片描述
  • 可以看到此时程序刚从主函数入口进入,变量a在内存中已经开辟好了空间。但还没有开始执行下一条int a = 0x11223344的赋值操作。所以a的值是一个随机值1.
  • 我们接着执行
    在这里插入图片描述
  • 这里还没有执行int a = 0x11223344的赋值操作,但是已经为main函数开辟好了栈帧空间。把局部变量都赋值为了cc cc cc cc,所以a这时候还是随机值-858993460。
    在这里插入图片描述
  • 继续执行了下一步赋值操作0x11223344的十进制数就是287454020.
  • 可以看到此时在内存中a的地址为 44 33 22 11
  • 正好是0x11 22 33 44 倒着写过来的。
  • 所以在内存中的存储就是把16进制位按每一个字节(即八个bit位)倒着写上去就行了。
    我们来看看官方怎么描述。

把某些机器选择在存储器上按照从最低有效字节到最高有效字节的顺序存储对象的方法叫做小端法。(我们现在大多数用这种方法)
而另一些机器则按照从最高有效字节到最低有效字节的顺序存储
对象
的方法叫做大端法

特别注意:字节在内存中的存储是从低地址向高地址存储的*

  • 例如: 用小端法存储0x11 22 33 44,11是一个字节,22,33,44都是一个字节(即二进制中的八个bit位)。11是最高字节位,44是最低字节位。按照从最低有效字节到最高有效字节的顺序存储0x11
    22 33 44得到 在内存中表示是44 33 22 11.
关于大小端之争的有趣故事

在这里插入图片描述

  • 由以上的铺垫,这里我们就要步入正题啦

🌳数据类型的详细介绍

  • 接下来先介绍一下都有什么数据类型,然后我们再对其中的整型类型和浮点类型进行剖析。由于博主水平有限。其他暂时了解即可。

整型类型(剖析)

  • 每个整型可以具体划分为有符号整型和无符号整型。
  • 有符号数的特点
  • 有正负之分。取值范围从负数到正数
  • 二进制位的最高位是符号位。0表示正数,1则表示负数。
  • 无符号数的特点
  • 全是正数,无正负之分。取值范围从0到正数。
  • 二进制位的最高位不是符号位,它的最高位仅用表示该数的大小
  • 32位机器上C语言的整型数据类型的典型取值范围。
    在这里插入图片描述
  • 我们可以看到有unsigned全是正数,就入上面我们所说的那样。
char
 unsigned char//无符号字符类型
 signed char//有符号
short
 unsigned short [int]
 signed short [int]
int
 unsigned int
 signed int
long
 unsigned long [int]
 signed long [int]

浮点数类型(剖析)

float
double

构造类型(了解)

> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union

指针类型(了解)

int \*pi;
char \*pc;
float\* pf;
void\* pv;

空类型(了解)

void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。

🌳整型在内存中的存储:原码,反码,补码

  • 我们前面说到一个变量a=0x11223344在内存中是如何存储的了。
  • 但是负数怎么存储呢?
  • 例如:
int a = 10;
int b = -10;

  • 这个int b = -10怎么在内存中存储呢?
  • 我们知道为 b分配四个字节的空间。
    那如何存储?
  • 下面了解下面的概念:
  • 计算机中的整数有三种表示方法,即原码、反码和补码。
  • 三种表示方法均有符号位数值位两部分
  • 符号位都是用0表示“正”,用1表示“负”,而数值位负整数的三种表示方法各不相同。

原码
直接将二进制按照正负数的形式翻译成二进制就可以。
反码
将原码的符号位不变,其他位依次按位取反就可以得到了。
补码
反码+1就得到补码。

  • 重点:
  • 正数的原、反、补码都相同。
    负数的原、反、补码不相同。
    对于整形来说:数据存放内存中其实存放的是补码。
    为什么呢?
  • 在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统
    一处理;
  • 同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
  • 我们拿上面的a = 10和 b = -10 为例,来探究数在内存中是如何存储的。
    在这里插入图片描述
  • 可以看到a的值是00 00 00 0a。a是用10进制表示就是数字10。
  • b的值是ff ff ff fa,转化为10进制就是4294967290,天呐好大的数字!为什么不是-10呢?
  • 让我们来探究一下
00000000 00000000 00000000 00001010 二进制表示的a
11111111 11111111 11111111 11110110 二进制表示的b

  • 对于a ,因为数据在内存中存放的是补码。但a为正数,原,反,补码都相同。所以内存中存的就是10的二进制原码。
00000000 00000000 00000000 00001010 数字10的二进制原码
转化成16进制就是00 00 00 0a

  • 对于b, b是一个负数-10,将-10放进内存中放的是-10的补码。
  • 我们经过对原码符号位不变,其他位按位取反得到反码,反码进行+1,就得到了补码
10000000 00000000 00000000 00001010 负10的原码
11111111 11111111 11111111 11110101 负10的反码(符号位不变,其他位按位取反)
11111111 11111111 11111111 11110110 补码 = 反码+1

  • 我们得到了-10的补码,发现和图片上的一样
    在这里插入图片描述
  • 转化成16进制的确是ff ff ff f6。
  • 但为什么打印出来的是-10呢?而不是他的二进制补码对应的数呢
  • 因为打印的话是以原码的形式打印的,但在内存中存储是以
    补码形式存储的
深入理解原码,反码,补码
  • 接下来我们用实例来理解原反补。
  • 下面程序运行的结果是什么?
  • 一共三部曲
#include<stdio.h>
int main()
{
		char a = -1;//默认为有符号
		signed char b = -1;//有符号char类型
		unsigned char c = -1;//无符号char类型
		printf("a=%d,b=%d,c=%d", a, b, c);//a = -1,b = -1,c = 255
		return 0;
}

1.先得到-1原来的原、反、补码
  • 剖析,以下是-1这个整数的(4个字节)原反补码。
10000000 00000000 00000000 00000001 原码
11111111 11111111 11111111 11111110 反码
11111111 11111111 11111111 11111111 补码//(补码就是反码+1)

2.发生截断
  • 我们拿到了-1这个整数的补码。因为内存中存的是补码,现在把4个字节的整型数字负1放进char类型变量a中的话,就要发生截断,只取低一个字节。即11111111(补码)。
11111111 截断后放在a中的补码

3.发生整形提升
  • 我们要以**%d**的形式打印a;必须先整型提升,整型提升看符号位,符号位是1,前面就补够32个1位置。符号位是0,前面就要补够32个0。(一个整型32位4个字节)
11111111 11111111 11111111 11111111 发生整型提升后的补码

    • 因为printf到屏幕上显示出来的是原码
  • 但a中放的是11111111 11111111 11111111 11111111(补码). 所以打印出来的a是10000000 00000000 00000000 00000001(原码)。
  • b = -1的原因同理。因为char和signed char道理一样。都是有符号字符类型
  • 我们再来看c为什么是255?
11111111 11111111 11111111 11111111 这是-1的补码

重点在于变量c!!

  • c为什么是255?因为c是unsigned char类型,无符号意味着他个正数。最高位不是符号位。无符号数在整型提升的时候和有符号位不一样。它是在前面全补0。
11111111 11111111 11111111 11111111 这是-1补码
11111111 放进变量c截断后的补码
00000000 00000000 00000000 11111111整型提升后的补码

  • 然后以%d的形式打印出来的话,就要把补码转化成原码
00000000 00000000 00000000 11111111整型提升后的补码
但计算机认为最高位是0,所以这时候的补码是个正数。
原码反码补码相同。

  • 所以打印出来就相当于是00000000 00000000 00000000 11111111(即255)。
  • 学到了没有?那我们来检验一下学习成果,再来一道题
#include <stdio.h>
int main()
{
	char a = -128;
	printf("%u\n", a);//a = 4294967168
	return 0;
}

1.先拿到-128的补码,用我们的原反补计算。

10000000 00000000 00000000 10000000 原码
11111111 11111111 11111111 01111111 反码
11111111 11111111 11111111 10000000 这是-128的补码

  1. 放到char类型中需要截断
10000000 截断后的补码

  1. 发生整型提升后的补码

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

1 11111111 01111111 反码
11111111 11111111 11111111 10000000 这是-128的补码


2. 放到char类型中需要截断



10000000 截断后的补码


3. 发生整型提升后的补码





[外链图片转存中...(img-gR28prGT-1715540875827)]
[外链图片转存中...(img-BMZVi0Y7-1715540875828)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值