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

目录

  • 一.数据类型
  • 二.整形在内存中的存储
    • 1.整数的源码、反码、补码
    • 2.隐式类型转化(重点理解)
    • 3.深入理解变量内容的存入和取出(重点)
    • 4.大端与小端存储方式
    • 5.各个类型的取值范围
    • 5.数据存储笔试题
  • 三.浮点数在内存中的存储
    • 1.浮点数存储规则
    • 练习:

一.数据类型

C语言深度解剖之数据到底在内存中如何存储_第1张图片
类型的意义:

  1. 使用这个类型开辟内存空间的大小。
  2. 决定该类型数据在内存中如何存储。
    C语言深度解剖之数据到底在内存中如何存储_第2张图片
    整形数据类型:
    C语言深度解剖之数据到底在内存中如何存储_第3张图片
    浮点数数据类型:
    C语言深度解剖之数据到底在内存中如何存储_第4张图片

二.整形在内存中的存储

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

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

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

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

C语言深度解剖之数据到底在内存中如何存储_第5张图片

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

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

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

原因:

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

加法减法到底是如何统一运算呢,这里举个例子:
20-10 就可以转化为 20+(-10) 两个数的补码进行相加
C语言深度解剖之数据到底在内存中如何存储_第6张图片
总结:
所有的整数在内存中存储都是以补码的形式存储,有符号的整数,与无符号数的原码、反码、补码相同,而负整数的原码、反码、补码要经过计算,为什么整数在内存中要以补码的形式存储,根本原因就是将减法也统一成加法(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中。
下图,描述了整个过程一定一定要理解
C语言深度解剖之数据到底在内存中如何存储_第7张图片
C语言深度解剖之数据到底在内存中如何存储_第8张图片
我们都知道一个有符号的char 它的取值范围为 [-128 ~127 ] ,其实你不管给char类型的变量赋值一个多大的整数,但在存储在该变量的值一定是在 [-128 ~127 ]范围内,其根本原因就是char 类型只有8位,将一个整形的数据放入一定会产生截断。

例题:
C语言深度解剖之数据到底在内存中如何存储_第9张图片
其实这里的出现这种情况的根本原因是char 类型的变量,或者短整形的变量,把存进来的最高位1,当成了符号位所以是一个负数。

证明存在整形提升:
C语言深度解剖之数据到底在内存中如何存储_第10张图片
算术转化

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。
C语言深度解剖之数据到底在内存中如何存储_第11张图片

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

下面思考一个问题:
C语言深度解剖之数据到底在内存中如何存储_第12张图片
或者直接是这样:
C语言深度解剖之数据到底在内存中如何存储_第13张图片
既然你说一个int类型与unsigned int 类型 的变量进行运算时,肯定b的类型也要转化为unsigned int 类型,那么问题来了,两个无符号数相加为什么能加出负数来呢。

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

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

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

C语言深度解剖之数据到底在内存中如何存储_第14张图片

C语言深度解剖之数据到底在内存中如何存储_第15张图片
C语言深度解剖之数据到底在内存中如何存储_第16张图片
C语言深度解剖之数据到底在内存中如何存储_第17张图片
总结:

  • 存数据

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

  • 取数据

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

C语言深度解剖之数据到底在内存中如何存储_第18张图片

4.大端与小端存储方式

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

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

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

  • 为什么有大端小端存储

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

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

C语言深度解剖之数据到底在内存中如何存储_第19张图片
检测一下我的电脑是什么存储模式
C语言深度解剖之数据到底在内存中如何存储_第20张图片

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

int a=1;
C语言深度解剖之数据到底在内存中如何存储_第21张图片

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;
}

C语言深度解剖之数据到底在内存中如何存储_第22张图片

5.各个类型的取值范围

signed char 类型的取值范围:
C语言深度解剖之数据到底在内存中如何存储_第23张图片
C语言深度解剖之数据到底在内存中如何存储_第24张图片

unsigned char 的取值范围:

C语言深度解剖之数据到底在内存中如何存储_第25张图片

其他类型以此类推
类型取值范围表:
C语言深度解剖之数据到底在内存中如何存储_第26张图片

5.数据存储笔试题

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

整形提升的规则:

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

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

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

C语言深度解剖之数据到底在内存中如何存储_第27张图片
在计算时,内存中是以补码的形式进行运算,记住补码发吗出来就是方便运算,所以这个整数的真正的值是它原码的大小,所以打印一定是打印整数的原码。

习题:

习题一:
C语言深度解剖之数据到底在内存中如何存储_第28张图片
答案:
在这里插入图片描述
具体分析:

C语言深度解剖之数据到底在内存中如何存储_第29张图片
无符号整形提升直接高位补0

习题二:
C语言深度解剖之数据到底在内存中如何存储_第30张图片
答案:
C语言深度解剖之数据到底在内存中如何存储_第31张图片
具体分析:
C语言深度解剖之数据到底在内存中如何存储_第32张图片
按整形(有符号与无符号)的形式打印时,若数据不够整形需要整形提升

习题三:
C语言深度解剖之数据到底在内存中如何存储_第33张图片
答案:
在这里插入图片描述
具体分析:
C语言深度解剖之数据到底在内存中如何存储_第34张图片
因为是以十进制的有符号数打印,整形提升之后,判断符号位是否为负数,若为负数要将补码转化为原码再化成十进制进行打印,若是整数直接转化为十进制打印(正数因为补码就是原码)

习题三:
C语言深度解剖之数据到底在内存中如何存储_第35张图片
答案:
无限循环

具体分析:
C语言深度解剖之数据到底在内存中如何存储_第36张图片
习题四:
C语言深度解剖之数据到底在内存中如何存储_第37张图片
答案:
C语言深度解剖之数据到底在内存中如何存储_第38张图片

具体分析:
C语言深度解剖之数据到底在内存中如何存储_第39张图片
C语言深度解剖之数据到底在内存中如何存储_第40张图片

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

习题五:
C语言深度解剖之数据到底在内存中如何存储_第41张图片

答案:
0~255 255 ~0无限循环C语言深度解剖之数据到底在内存中如何存储_第42张图片

具体分析:
C语言深度解剖之数据到底在内存中如何存储_第43张图片
无符号数,从内存中拿出来运算一定为正数,不管里面存储的是什么二进制序列(就算是负数的二进制补码)。

习题六:
C语言深度解剖之数据到底在内存中如何存储_第44张图片
答案:
C语言深度解剖之数据到底在内存中如何存储_第45张图片
具体分析:
C语言深度解剖之数据到底在内存中如何存储_第46张图片

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

先看一个例子:
C语言深度解剖之数据到底在内存中如何存储_第47张图片

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

1.浮点数存储规则

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

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

C语言深度解剖之数据到底在内存中如何存储_第48张图片
IEEE 754规定:
对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
C语言深度解剖之数据到底在内存中如何存储_第49张图片

对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
C语言深度解剖之数据到底在内存中如何存储_第50张图片
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在内存中如何存储:
C语言深度解剖之数据到底在内存中如何存储_第51张图片
浮点数0.5(E为负数)在内存中如何存储:
C语言深度解剖之数据到底在内存中如何存储_第52张图片

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

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

练习:

C语言深度解剖之数据到底在内存中如何存储_第53张图片
答案:
C语言深度解剖之数据到底在内存中如何存储_第54张图片
具体分析:
C语言深度解剖之数据到底在内存中如何存储_第55张图片
先看以整形的方式存,以浮点型取:

C语言深度解剖之数据到底在内存中如何存储_第56张图片
以浮点型存,整形取

C语言深度解剖之数据到底在内存中如何存储_第57张图片

你可能感兴趣的:(c语言,开发语言)