C语言深度解剖之数据到底在内存中如何存储

✅作者简介:嵌入式入坑者,与大家一起加油,希望文章能够帮助各位!!!!
📃个人主页:@rivencode的个人主页
🔥系列专栏:玩转C语言
💬推荐一款模拟面试、刷题神器,从基础到大厂面试题👉点击跳转刷题网站进行注册学习

一.数据类型

在这里插入图片描述
类型的意义:

  1. 使用这个类型开辟内存空间的大小。
  2. 决定该类型数据在内存中如何存储。
    在这里插入图片描述
    整形数据类型:
    在这里插入图片描述
    浮点数数据类型:
    在这里插入图片描述

二.整形在内存中的存储

1.整数的源码、反码、补码

计算机中的整数有三种表示方法,即原码、反码和补码。

三种表示方法均有符号位和数值位两部分,第一位符号位都是用0表示“正”,用1表示“负”,其余位为数值位。

正数的原码、反码、补码都相同

在这里插入图片描述

负整数的三种表示方法各不相同。

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

对于整形(有符号、无符号)来说:数据存放内存中其实存放的是补码

原因:

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路,也就是说只需要一套硬件电路就可以解决问题何乐不为。

加法减法到底是如何统一运算呢,这里举个例子:
20-10 就可以转化为 20+(-10) 两个数的补码进行相加
在这里插入图片描述
总结:
所有的整数在内存中存储都是以补码的形式存储,有符号的整数,与无符号数的原码、反码、补码相同,而负整数的原码、反码、补码要经过计算,为什么整数在内存中要以补码的形式存储,根本原因就是将减法也统一成加法(1-1 == 1+(-1) ),计算机中只有运算加法的硬件。

2.隐式类型转化(重点理解)

要想彻底理解整形在内存中的存储,就一定一定要理解

表达式计算时,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。

整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。 因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。

一句话就是运算过程中,数据要传输到CPU中的寄存器进行运算,而32位的CPU的寄存器为32位,所以像char这种8位不满32的数据,要先整形提升为32位数据,再送入CPU中运算,而整形提升是计算机帮我们做的所以叫隐式类型转化。

整形提升的规则:

整形提升是按照变量的数据类型的符号位来提升的

整形提升肯定是补码,因为存放在内存中的就是补码。

  • 负数的整形提升
    高位补充符号位,负数的符号位就为1,所以高位补1补满32位
  • 正数的整形提升
    高位补充符号位,正数的符号位就为0,所以高位补0补满32位
  • 无符号整形提升,高位直接补0

示例:

char a=127;
char b=2;
char c=0;
c=a+b;
printf("%d\n",c);

a和b的值被提升为普通整型,然后再执行加法运算,加法运算完成之后,结果将被截断,然后再存储于c中。
下图,描述了整个过程一定一定要理解
在这里插入图片描述
在这里插入图片描述
我们都知道一个有符号的char 它的取值范围为 [-128 ~127 ] ,其实你不管给char类型的变量赋值一个多大的整数,但在存储在该变量的值一定是在 [-128 ~127 ]范围内,其根本原因就是char 类型只有8位,将一个整形的数据放入一定会产生截断。

例题:
在这里插入图片描述
其实这里的出现这种情况的根本原因是char 类型的变量,或者短整形的变量,把存进来的最高位1,当成了符号位所以是一个负数。

证明存在整形提升:
在这里插入图片描述
算术转化

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。
在这里插入图片描述

如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。

下面思考一个问题:
在这里插入图片描述
或者直接是这样:
在这里插入图片描述
既然你说一个int类型与unsigned int 类型 的变量进行运算时,肯定b的类型也要转化为unsigned int 类型,那么问题来了,两个无符号数相加为什么能加出负数来呢。

先抛出问题,等讲完变量内容的存入和取出再来讲上面那个问题。

3.深入理解变量内容的存入和取出(重点)

unsigned int a= -10 ,-10是如何存储在变量a中,如何取出

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结:

  • 存数据

字面数据必须先转成补码,在放入空间当中。所以所谓符号位,完全看数据本身是否携带±号。和变量有符号还是无符号无关

  • 取数据

一定要先看存储数据的变量本身类型,然后才决定要不要看最高符号位。如果变量是有符号的类型(比如 signed int),则如果符号位为1 则需要将补码转化成原码,若符号为0 直接二进制转成十进制 (正数的原码就等于补码),如果不需要(比如unsigned int),直接二进制转成十进制(无符号数原码也等于补码)。

在这里插入图片描述

4.大端与小端存储方式

计算机存储方式分为两种:大端存储 与 小端存储

大端存储: 是指数据的低位(从右往左由低到高) 存储在内存的高地址中,而数据的高位存储到内存的低地址中。
小端存储:是指数据的低位(从右往左由低到高) 存储在内存的低地址中,而数据的高位存储到内存的高地址中。

为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址,也就是说一个字节的内存单元有一个地址

  • 为什么有大端小端存储

在C语言中除了8 bit的char之外,还有16 bit的short型,32 bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

例如:
定义一个整型变量 int a=0x44332211;
看看变量a在内存中如果存储

在这里插入图片描述
检测一下我的电脑是什么存储模式
在这里插入图片描述

接下来就要判断计算机存储方式是小端还是大端
定义一个整型变量a

int a=1;
在这里插入图片描述

int Check_Sys1()
{
	int a=1;
	return *(char *)&a;
}
int main()
{
	int ret=Check_Sys2();
	if (1==ret)
	{
		printf("小端模式\n");
	}
	else
   	{
		printf("大端模式\n");
	}
  return 0;
}

在这里插入图片描述

5.各个类型的取值范围

signed char 类型的取值范围:
在这里插入图片描述
在这里插入图片描述

unsigned char 的取值范围:

在这里插入图片描述

其他类型以此类推
类型取值范围表:
在这里插入图片描述

5.数据存储笔试题

在做题之前,有关整形提升,还有整数的原码、反码、补码的概念搞的清清楚楚,不然做题会有问题

整形提升的规则:

整形提升是按照变量的数据类型的符号位来提升的

整形提升肯定是补码,因为存放在内存中的就是补码。

  • 负数的整形提升
    高位补充符号位,负数的符号位就为1,所以高位补1补满32位
  • 正数的整形提升
    高位补充符号位,正数的符号位就为0,所以高位补0补满32位
  • 无符号整形提升,高位直接补0

在这里插入图片描述
在计算时,内存中是以补码的形式进行运算,记住补码发吗出来就是方便运算,所以这个整数的真正的值是它原码的大小,所以打印一定是打印整数的原码。

习题:

习题一:
在这里插入图片描述
答案:
在这里插入图片描述
具体分析:

在这里插入图片描述
无符号整形提升直接高位补0

习题二:
在这里插入图片描述
答案:
在这里插入图片描述
具体分析:
在这里插入图片描述
按整形(有符号与无符号)的形式打印时,若数据不够整形需要整形提升

习题三:
在这里插入图片描述
答案:
在这里插入图片描述
具体分析:
在这里插入图片描述
因为是以十进制的有符号数打印,整形提升之后,判断符号位是否为负数,若为负数要将补码转化为原码再化成十进制进行打印,若是整数直接转化为十进制打印(正数因为补码就是原码)

习题三:
在这里插入图片描述
答案:
无限循环

具体分析:
在这里插入图片描述
习题四:
在这里插入图片描述
答案:
在这里插入图片描述

具体分析:
在这里插入图片描述
在这里插入图片描述

解决这个题目的重点就是,不管你往char 类型的变量中放什么整数,都在[ -128~127 ]范围之内。

习题五:
在这里插入图片描述

答案:
0~255 255 ~0无限循环请添加图片描述

具体分析:
在这里插入图片描述
无符号数,从内存中拿出来运算一定为正数,不管里面存储的是什么二进制序列(就算是负数的二进制补码)。

习题六:
在这里插入图片描述
答案:
在这里插入图片描述
具体分析:
在这里插入图片描述

三.浮点数在内存中的存储

先看一个例子:
在这里插入图片描述

虽然两个数据的值一样,但变量的类型不一样则导致在内存中存储的形式就有巨大差异。

1.浮点数存储规则

根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:

(-1)^S * M * 2^E
(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
M表示有效数字,大于等于1,小于2。
2^E表示指数位。

在这里插入图片描述
IEEE 754规定:
对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
在这里插入图片描述

对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
在这里插入图片描述
IEEE 754对有效数字M和指数E,还有一些特别规定。

IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是多一位有效数字。

E为一个无符号整数(unsigned int)
这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0 ~2047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127对于11位的E,这个中间数是1023,比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。

浮点数5.5在内存中如何存储:
在这里插入图片描述
浮点数0.5(E为负数)在内存中如何存储:
在这里插入图片描述

指数E从内存中取出:
E全为0
说明原来我们E=0-127 =-127,数据的数量级为 1*2^-127 直接表示为趋近与0的数据。
E全为1
说明原来我们E=255-127=128,数据的数量级为 1*2^128 直接表示为无穷大的数据。

由此可知float类型的取值范围应该在:
E为全1 ,在加上前面的正负号,就是取值范围
在这里插入图片描述

练习:

在这里插入图片描述
答案:
在这里插入图片描述
具体分析:
在这里插入图片描述
先看以整形的方式存,以浮点型取:

在这里插入图片描述
以浮点型存,整形取

在这里插入图片描述

  • 55
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 62
    评论
"C语言深度解剖"是一本PDF电子书,它在内容上对C语言进行了全面而深入的剖析和解析。该电子书以书签的形式提供,这使得读者可以方便地浏览和导航书的各个章节。 书的内容涵盖了C语言的各个方面,包括基本语法、数据类型、运算符、控制语句、函数、指针等。每个章节都提供了详细的解释和示例,以帮助读者更好地理解和掌握C语言的各个概念和特性。 书签功能使得读者可以迅速定位到感兴趣的章节或部分。通过点击书签,读者可以跳转到所选章节的开头或指定的页面,从而节省时间并提高阅读效率。 对于初学者来说,"C语言深度解剖"提供了一个系统而详细的学习资源。读者可以按照自己的学习进度,逐步阅读不同章节,并通过书签功能进行快速导航。这种结构化的学习方式有助于初学者建立起对C语言的整体认识和理解。 对于有一定C语言基础的读者来说,"C语言深度解剖"也是一个很好的参考书籍。书对于一些较为复杂或深奥的知识点进行了深入分析和讲解,可以帮助读者更深入地理解C语言的工作原理和内部机制。 总之,"C语言深度解剖"是一本内容详尽、结构清晰、带有书签功能的PDF电子书,适合不同层次的读者学习和参考。无论是初学者还是有经验的C语言开发者,都可以从获取到有益的知识和信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

rivencode

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

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

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

打赏作者

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

抵扣说明:

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

余额充值