【C语言】_8.数据的存储

news/2024/10/24 0:22:25/

正文:
1.数据类型介绍

前面我们已经了解到基本的内置类型:

char      //字符数据类型   1个字节
short     //短整型        2个字节
int       //整型          4个字节
long      //长整型        4或8个字节
long long //更长的整型    8个字节
float     //单精度浮点数  4个字节
double    //双精度浮点数  8个字节

类型的意义是:

(1)使用这个类型开辟内存空间的大小(大小决定了使用范围);

(2)决定了看待内存空间的视角;

1.1 类型的基本归类

(1)整型:

char            //char虽然是字符类型,但是字符类型存储的时候,存储的字符的assic码值是整数unsigned char   //无符号的charsigned char     //有符号的char
//C语言未规定char c1时有无符号,取决于编译器。大部分编译器都默认char等价于signed char;shortunsigned short [int]signed short [int]
//规定short s1等价于signed short s1;intunsigned intsigned int
//规定int s1等价于signed int s1;longunsigned long [int]signed long [int]
//规定long s1等价于signed long s1;

(2)浮点数:

float
double
//在C99标准中,也有了long double类型

 (3)构造类型(自定义类型):

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

(4)指针类型:

int* pi;
char* pc;
float* pf;
void*pv;
//指针变量就是用来存放地址的

(5)空类型

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

2.整型在内存中的存储

2.1 原码、反码、补码

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

三种表示方法都有符号位和数值位两部分,符号位0正1负,而数值位直接进行表示。

(1)负整数的三种表示方法各不相同:

原码:直接将数值按照正负数的形式翻译成二进制;

反码:符号位不变,其余位直接取反;

补码:反码+1;

(2)正整数原码、反码、补码都相同;

int main()
{int a = 10;//原码:00000000000000000000000000001010//反码:00000000000000000000000000001010//补码:00000000000000000000000000001010int b = -10;//原码:10000000000000000000000000001010//反码:11111111111111111111111111110101//补码:11111111111111111111111111110110return 0;
}

对于整型数据来说,内存中存放的是数据的补码。

原因:

比如我们计算1-1,CPU只有加法器,只能进行加法运算,故而转化为计算1+(-1),如果内存中存放的是数据的原码,则计算的是:
000000000000000000000000000000000001+100000000000000000000000000000000001=

100000000000000000000000000000000010即-2

故而用原码计算是错误的。

如果内存中存放的是数据的补码:

000000000000000000000000000000000001+1111111111111111111111111111111111111111=

100000000000000000000000000000000,此时最高位的1无处可存而丢失,答案为1,正确。

可以联想char类型:

再举一例:

2.2 大小端

大小端全称叫大小端字节序存储。

int a=0x11223344;

 

 在VS中,采取小端字节序存储。

调试查看内存:

原因:

为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元
都对应着一个字节,一个字节为8
但是在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处理器还可以由硬件来选择是大端模式还是小端模式

我们也可以写函数来判断大小端

 例题:
例1:

解析:

-1原码为10000000000000000000000000000001 

   反码为1111111111111111111111111111111111110

   补码为1111111111111111111111111111111111111

补码存在有符号char类型的a中去,char类型一个字节8个比特位,故而a中实际存的是11111111(低八位),而在打印中,%d打印的是有符号的整型,也就是四个字节,位数不够,故而需要整型提升,补的是原来符号的符号位,故而提升为1111111111111111111111111111111111111,打印有符号数,提升后仍未补码,故而求原码,先-1再保持符号位不变,其他位取反,最终结果为-1;

在VS中,char等同于signed char ,故而输出仍未-1;

而对于unsigned char 类型来说,得到全1的-1的补码,取低八位的11111111,%d打印有符号的整型,故而需要按照原来符号的符号位进行整型提升,原来符号类型为unsigned int,故而默认为内存中存放的是无符号数,高位直接补0,故而整型提升为00000000000000000000000011111111,提升后仍为补码,故而求原码,最高位为0为整数,原反补码相同,故而原码仍为该数,输出结果为255.

例2:

 解析:

 例3:

 类似于例2易得运行结果,此处不再做详细解释。

例4:

 解析:

 例5:

注:代码运行速度过快,故而采用了Sleep 

例6:

 例7:

经过几道例题的演示,我们容易发现无符号类型如unsigned char、unsigned int 非常容易出现死循环,所以在我们写代码的时候,尽可能避开定义无符号类型。

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

 浮点数包括float、double、long double等。

首先介绍两个文件:

(1)float.h:定义了浮点数取值范围的相关信息;

(2)limits.h定义了整型数据取值范围的相关信息:如:

 

举一例:

 接下来详细阐述浮点数在内存中的存储:

根据国际标准IEE754,任意一个二进制浮点数V可以表示成下面的形式:(-1)^S*M*2^E

(-1)^S表示符号位,当S=0时,V为整数;当S=1,V为负数 ;M表示有效数字,M∈(1,2);2^E表示指数位

 比如十进制浮点数5.5表示为二进制:小数点前5表示为101,小数点后位依次为2^-1,2^-2......故而5.5表示为101.1,化作标准格式为:(-1)^0*1.011*2^2

比如十进制的9.0表示为二进制为1001.1,转化为标准格式为:(-1)^0*1.001*2^3;

而并非所有的浮点数都能在内存中精确保存,可能需要小数点后很多位才能接近原本的浮点数,其实浮点数在内存中的存储是存在误差的。

在内存中存储浮点数时,存储的并不是完整的二进制序列,而是存储的SME。

IEEE规定,对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。

 对于64位的浮点数,最高的1位是符号位S,接下来的11位是整数E,剩下的52位为有效数字M。

(此处双精度浮点数存储模型不再做详细表示)

IEEE对于有效数字M和E还有一些特殊规定:
对于M,易知M首位总是1,故而在存储时可以舍弃首位的1,直接保存后面的数字,比如保存1.01时,就可以舍弃1,只保存后面的01,等到读取的时候,再把前面的1加上去。这样就可以节省1位有效数字。

对于E,

(1)存放E时:

E作为一个无符号整数,如果E是8位,则取值范围是0~255,如果E是11位,则取值范围是0~2047,但是我们知道科学计数法中的E可以是负数,所以存入内存时E的真实值必须加上一个中间数,对于8位的E,中间数为127,对于11位的E,这个中间数是1023。比如,2^10的E是10,所以保存为32位浮点数时,保存为127+10=137,即10001001。

我们可以进行验证:

 调试查看内存:

 (2)取出E时:

第一种情况:当E不全为0或不全为1时,内存中存的E减去127或1023,得到真实值,再将M前的有效数字1加上,就是初始值;

第二种情况:E全为0时,此时浮点数E的值等于1-127(或1-1023)即为真实值,有效数字M还原也不再加上1,直接还原储存的小数,这样做是为了表示±0以及无限接近0的数字。

第三种情况:E全为1时,此时如果数字M全为0,表示±∞,正负号取决于S。

在对整型和浮点数在内存中的存储有了基本了解后,现在来解决前文遗留的一个问题:

解析:

 注意:当两个浮点数在内存中没有精确保存,那么这两个浮点数是不能直接用等号比较相等的。

比如:

int main()
{float f = 0.0001;if (f == 0.0){}return 0;
}

 在上述代码中,f==0.0语句是不正确的,因为该浮点数在内存中的存储可能存在误差导致错误,在这种情况下,我们通常进行相减,判断差值是否在允许的范围内;

||终


http://www.ppmy.cn/news/153377.html

相关文章

如何设计云存储服务端数据存储加密机制

云存储是一种新型的网络存储形式。随着云存储的广泛使用,云存储中的数据安全问题,如数据泄漏、数据篡改,如何设计云存储服务端数据存储加密机制也成了用户广泛关注的问题。云存储可以分为访问层、应用接口层、基础管理层和存储层,…

数据中心存储架构-刘新民(数据中心 存储)

数据中心存储架构 文/刘新民 存储系统是数据中心IT环境的核心基础架构,是数据中心数据访问的最终承载体。存储在云计算、虚拟化、大数据等相关技术进入后已经发生了巨大的改变,块存储、文件存储、对象存储支撑起多种数据类型的读取;集中式存…

3-1存储系统-存储器概述主存储器

文章目录 一.存储器概述(一)存储器分类1.按在计算机中的作用(层次)分类2.按存储介质分类3.按存取方式分类4.按信息的可保存性分类 (二)存储器的性能指标 二.主存储器(一)基本组成1.译…

十一.数据的存储(1)

如果说前面的章节是C语言的初阶的话,那么从本章开始就要进入C语言的进阶部分了。经过了以前C语言初阶的学习。如果说前面初阶的内容是建立一个基本的框架 ,那么后面的进阶部分则是不断的细化、完善这个框架,让我们对C语言的理解更进一步。话不…

2022年5月30日STM32——存储器 和 I2C读写EEPROM

此内容仅是为了自己方便回忆,内容来源于野火指南者开发板教程。 一.存储器 RAM(Random Access Memory)随机存储器:当存储器中的消息被读取或写入时,所需要的时间与这段信息所在的位置无关。 RAM分为动态…

c语言数据存储 详细版

数据的存储(主讲整型和浮点型) 每一小部分后面都有大量的面试题,为了你进行加深巩固知识,另外提醒一下,char其实本质上是整型,因为他的实现是 ASCLL码值 下文有: 整型存储浮点存储原码,补码,反码试题精讲面试题和大小端存储 1整型在内存中的存储 无符号数 (一定是大于等于0…

03 数据载入、存储及文件格式

目录 1. 文本格式数据的读写 1.1 分块读入文本文件 1.2 将数据写入文本格式 1.3 使用分隔格式 1.4 JSON数据 1.5 XML和HTML:网络抓取 1.5.1 使用lxml.objectify解析XML 2. 二进制格式 2.1 使用HDF5格式 2.2 读取Microsoft Excel文件 3. 与Web API交互 4…

96、数据的存储

运行实例: 在debug和release两种模式下,进行代码运行,debug下 i 的地址是大于arr[9] 的地址的,release 下i 的地址是小于arr[9] 的地址。原因是:release状态进行了优化处理。 C语言中基本的内置类型 整形数据类型 char …