C语言—深度剖析数据在内存中的存储

数据类型介绍

前面我们已经学习了基本的内置类型:

char        //字符数据类型
short       //短整型
int         //整形
long        //长整型
long long   //更长的整形
float       //单精度浮点数
double      //双精度浮点数
//C语言有没有字符串类型?

以及他们所占存储空间的大小。

类型的意义:

  1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。
  2. 如何看待内存空间的视角。

类型的基本归类

整型家族

char
//本质是ASCII码值,是整型,所以划分到整型家族
 char
 unsigned char
 signed char
 //char到到底是signed char还是unsigned char取决于编译器
short
 unsigned short [int]
 signed short [int]
int
 unsigned int
 signed int
long
 unsigned long [int]
 signed long [int]

下面的类型只要是没标unsigned都是有符号的

生活中有很多数据都是没有负数的

身高、体重、长度

int a = 10;
a是一个整型,有符号的整型,一个整形是四个字节=32bit
00000000 00000000 00000000 00001010
最高位即为符号位,符号位是0表示正数

浮点型家族

float
//精度低,存储范围小
double

构造类型

> 数组类型    int[5]
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union

指针类型

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

空类型

void 表示空类型(无类型)

通常应用于函数的返回类型、函数的参数、指针类型。


整型在内存中的存储

我们之前讲过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。

int a = 20;
int b = -10;

我们知道为 a 分配四个字节的空间。

那如何存储?

下来了解下面的概念:

原码、反码、补码

计算机中的整数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用 0 表示“正”,用 1 表示“负”,而数值位负整数的三种表示方法各不相同。

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

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

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

对于整形来说:数据存放内存中其实存放的是补码。

为什么呢?

在计算机中,正数的原码、反码和补码都相同,因为它们的符号位都是 0。而在计算机系统中,数据一般以补码的形式存储在内存中。这是因为补码表示方式有以下优势:

  • 统一处理符号位和数值域,简化处理逻辑。
  • 加法和减法可以统一处理,无需额外的硬件电路。
  • 只需要加法器,减法可以转换为加法操作。

内存中存储顺序可能与预期不同,这可能受计算机的字节序影响,即小端序和大端序的差异。因此,观察到变量存储的补码顺序不对劲可能是因为字节序不同导致的。

大小端存储

什么大端小端:

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址 中;

小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地 址中。

为什么有大端和小端:

为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元 都对应着一个字节,一个字节为8 bit。但是在C语言中除了8 bit的char之外,还有16 bit的short型,32 bit的long型(要看具体的编 译器),另外,对于位数大于8位 的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如 何将多个字节安排的问题。因此就 导致了大端存储模式和小端存储模式。 例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为 高字节, 0x22 为低字节。对于大端 模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。小端模式, 刚好相反。我们常用的 X86 结构是 小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以 由硬件来选择是大端模式还是小端 模式。

注意:一个字节没有大小端顺序的

如何查看自己的编译器是大端还是小端呢,实际上也十分简单

int main()
{
	int n = 1;
	char* p = &n;
	if(*p == 1)
	    printf("小端储存");
	else
		printf("大端储存");
}

浮点型在内存中的存储

常见的浮点数:

3.14159

1E10

浮点数家族包括: float、double、long double 类型。

浮点数表示的范围:float.h中定义

IEEE754标准32位浮点数

这篇文章原文是在CSDN上写的,并没有使用markdown格式编辑

原文链接快速了解—IEEE754标准32位浮点数的转换-CSDN博客

IEEE754标准的介绍网上有好多,这里就不过多介绍了,这篇文章主要讲的是浮点数转换的方法,大家认真看马上就能掌握了

但是我们还需需要了解

什么是IEEE754标准的32位浮点数

计算机存储的方式主要有两种,分别是定点数和浮点数

那存储的内存就那么多,怎么样才能存储更多的位数呢?

科学家们就很聪明,通过科学计数法来创造了浮点数的存储

好,说了那么多,感兴趣了了解一下就行

那么需要我们记住的是,定点数存储的范围小,但是精确;浮点数存储的范围更大,但是不精确

浮点数的表示

一个浮点数 (Value) 的表示其实可以这样表示:

也就是浮点数的实际值,等于符号位(sign bit)乘以指数偏移值(exponent bias)再乘以分数值(fraction)。

哈哈,有点难,我也看不懂

那我们看这个

我们可以这样理解,任何一个二进制数,都可以表示为

这个要怎么理解呢,看上面那幅图十进制的1.75转化为二进制的表示

当然上面那幅图指数是二进制,实际上我们写的时候写成十进制可能更好去理解,那

十进制是 小数X10的几次方

二进制当然就是 小数X2的几次方

理解的方式自然也是一样的,乘上正数次方,小数点向右移动,乘上负数次方,小数点向左移动。

储存方式

我们有三十二位地址,也就是4byte(32bit)

如果大家感兴趣后面单独出一个文章来讲32位和64位到底是什么意思

那该如何存储呢?

IEEE754规定:在32位浮点数中,符号位为第一位,指数位是后面八位,小数位是后面的23位

符号位

0为“+”,1为“-”,也就是说第一位是0,就说明这个数是个正数,第一位是1,就说明是负数

如何去记呢

很简单,因为0就说明什么也没有,所以如果是正数的话我们不会过多去关注,是负数我们才需要去标记一下,也就是在前面加上1.

指数位(阶码)

在 IEEE 754 浮点数标准中,阶码是用移码表示的,移码的定义:移码 = 真值 + 偏置值;

在 IEEE 754 标准中,移码的偏置值是 2^(n-1)-1

这个是什么意思呢,其实也很简单,我们需要的是真值,根据上面的式子很容易就能得出:

真值 = 移码 - 偏置值

所以在三十二位浮点数中,阶数(指数)一共有八位,所以真正的指数就可以表示为

真正的指数 = 32位浮点数从前往后第二位到第九位的二进制数 - 2^(8-1)-1

再算一下

指数 = 八位阶数 - 127

小数位(尾数)

小数位,大家可以思考一下,如果必须开头都是1,那么我们是不是可以从第二位开始储存,第一位默认为1,以此来获得更大的存储空间呢?

在 IEEE 754 浮点数标准中,尾数码部分采用原码表示,且尾数码隐含了最高位 1,在计算时我们需要加上最高位1,即 1.M

IEEE754标准的32位浮点数的转换

介绍了那么多,接下来我们来一起看看实战的例子

IEEE754标准格式存储的十六进制浮点数转换成十进制的数值

41360000

首先,我们先把十六进制转化为2进制,十六进制,每一位都能转化成4位二进制,就比如说4能转化成0010,1能转化成0001,分别写出来连起来就好

0 100 0001 0 011 0110 0000 0000 0000 0000

我们按照上面讲的,把32位浮点数划分为1、8、23,三组数字,然后一组一组看

符号位:0

表示32位浮点数是一个正数

指数位(阶码):1000 0010

转化成十进制,2的7次方加上2的1次方,为130

注意:此时的130为移码,指数的真值为移码减去偏置值

也就是 130 - 127 = 3

小数位(尾数):011 0110 0000 0000 0000 0000

因为尾数储存的时候省略了1,所以这个数应该看作

1.011011

好的,那么这个浮点数三个部分我们都知道了,那么组合起来就是这个数的十进制数值

理解起来很简单,就是正数,二进制数乘上2的3次方,和科学计数法一样,正3次方,小数点往后移动三位就行,表示出来就是

1011.011

那么,转化为十进制

= 11.375

所以11.375就是最终的结果

十进制化为二进制浮点数表示就是把整体逻辑反过来了,这里就不举例子了

特殊情况

形式指数小数部分
00
非规约形式0非0
规约形式1到 任意无穷
00NaN
非零
  • 32
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

J.Pei

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

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

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

打赏作者

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

抵扣说明:

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

余额充值