当前位置: 首页 > news >正文

数据储存方式

一、数据类型归类

整形家族:

char(本质是ASCII码值,为整形)
unsigned char
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]

long long

        unsigned long long [int]

        signed long long [int]

浮点数家族:

float
double

构造类型:

> 数组类型 (例:int arr[5],类型为int [5])
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union

指针类型:

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

空类型:

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

//第一个void表示无返回值
//第二个void表示函数无任何操作
void function(void)
{}

二、整形在内存中的存储

1.整数的表示形式

  • 二进制:0b___(0b10101)         
  • 八进制:0___(025)        格式化输出:%o
  • 十进制:___(21)            格式化表示:%d
  • 十六进制:0x___(0x15) 格式化表示:%x

2.原码、反码、补码

整数有三种2进制表示方法:原码、反码和补码

三种表示方法均有符号位数值位两部分,最高位为符号位

符号位:用0表示“正”,用1表示“负”,

数值位:正数的原、反、补码都相同;负整数的三种表示方法各不相同。

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

举例:

整型,在32位平台下占4个字节,32个比特位

如正整数5,它的原码、反码、补码都相同,如下:

原码:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1

反码:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1

补码:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1

而负整数5,它的原码、反码、补码却是这样的:

原码:1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1

反码:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0

补码:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1

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

为什么在计算机系统中,数值一律用补码来表示和存储呢?

1.可以将符号位和数值域统一处理;

2.加法和减法可以统一处理(CPU只有加法器)

3.补码与原码相互转换,其运算过程是相同的(原码=》补码和补码=》原码 可以使用同一种方法),不需要额外的硬件电路。

char类型在内存中的存储:

三、大小端存储模式

我们发现内存中n补码的存储顺序似乎不太正确,这其实就跟大小端存储有关

  • 大端(存储)模式:数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中
  • 小端(存储)模式:数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中

注意:大小端存储顺序是以字节为单位的,与字节内部的存储顺序无关

例子:

用代码判断是大端存储还是小端存储:

思路:定义 int n=1,char* p=(char*)&n,查看p地址处第一个字节的内容:是0,就是大端存储;是1,就是小端存储。

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

四、整型提升

CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,所以运算时需要将其转化为int或者unsigned int类型,即为整形提升:

有符号位的整形提升:

        负数:高位补充符号位,即高位全部补1

        正数:高位补充符号位,即高位全部补0

无符号位的整形提升:

        全部补0

例子:

//输出什么?
#include <stdio.h>
int main()
{char a = -1;signed char b = -1;unsigned char c = -1;printf("a=%d,b=%d,c=%d",a,b,c);return 0;
}

运行结果:

原因:

五、浮点数在内存中的存储

1.铺垫

任意一个二进制浮点数V可以表示成下面的形式:

(-1)^S * M * 2^E

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

简述:S用于判断正负号,M表示有效数字,E与小数点相关

举例:

2.存储形式

对于32位的单精度浮点数,最高一位为S,接着的8位是指数E,剩下的23位为有效数字M。

对于64位的双精度浮点数,最高一位为S,接着的11位是指数E,剩下的52位为有效数字M。

对于M的说明:

因为1≤M<2 ,可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。

所以,在保存M时,通常1都会省略掉,系统默认为1,这样可以节省一格bit位。

比如:保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。

对于E的说明:

E为一个无符号整数(unsigned int)

如果E为8位bit,它的取值为0-255,如果E为11位bit,它的取值为0-2047

但是,我们知道,科学计数法中的E是可以出现负数的。

所以,IEEE 754规定,存入内存时,E的真实值必须再加上一个中间数(最大取值的一半):

这个中间数在8位的E中是127,在11位的E中是1023。

比如:所以保存32位浮点数(float)时,若E=10,则保存成10+127 =137的二进制,即10001001

对于S的说明:

S可以决定小数是正数还是负数,如果存储的是正数,S为0,如果存储的是负数,S为1

举例:

3.浮点数从内存中取出

情况一:E的比特位不全为0或不全为1

当E不全为0或不全为1时,浮点数从内存中取出时,会将E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1

情况2:E比特位全为0(表示的数接近0)

如果E全为0,E等于 1-127=-126 或者 1-1023=-1022 即为真实值

有效数字M不再加上第一位的1,而是还原成0.xxxxxxx的小数

这样做是为了表示±0,以及接近于0的很小的数字。

情况3:E比特位全为1(表示的数正负无穷大)

如果有效数字M全为0,表示±无穷大(正负取决于符号位s)

4.浮点数存储的例子

#include <stdio.h>
int main()
{int n = 9;//0000 0000 0000 0000 0000 0000 0000 1001float* pFloat = (float*)&n;printf("n的值为:%d\n", n);//9//0 00000000 00000000000000000000101//S=0 E=-126 //还原为(-1)^0 * 0.00000000000000000000101 * 2^(-126)//非常接近于0printf("*pFloat的值为:%f\n", *pFloat);//0.000000*pFloat = 9.0f;//1001.0//(-1)^0 * 1.001 * 2^3//S=0 E=3 M=1.001//0 10000010 00100000000000000000000printf("num的值为:%d\n", n);//1091567616printf("*pFloat的值为:%f\n", *pFloat);//9.0return 0;
}


文章转载自:

http://WVzkIxjz.ndxmn.cn
http://ZrWpv2T5.ndxmn.cn
http://5z1QJj2Z.ndxmn.cn
http://ywpZynQd.ndxmn.cn
http://csDyOt4z.ndxmn.cn
http://m4fXO0AS.ndxmn.cn
http://vsQSYWME.ndxmn.cn
http://9tritSTm.ndxmn.cn
http://9jj2SlSQ.ndxmn.cn
http://fvPZ1YLc.ndxmn.cn
http://JS2iWAJY.ndxmn.cn
http://lnUtZRak.ndxmn.cn
http://2SO8QlQf.ndxmn.cn
http://RBAdCzx2.ndxmn.cn
http://QgadrYT9.ndxmn.cn
http://a9W9pqSC.ndxmn.cn
http://eNJBcMv3.ndxmn.cn
http://OnzhJXEk.ndxmn.cn
http://0CDF1BDN.ndxmn.cn
http://xPtzLb6H.ndxmn.cn
http://euWoNdAN.ndxmn.cn
http://BtiCkrKZ.ndxmn.cn
http://05KysrBT.ndxmn.cn
http://hmDe2jvw.ndxmn.cn
http://lgzJPMbT.ndxmn.cn
http://3Oum6e5R.ndxmn.cn
http://jp8la3cV.ndxmn.cn
http://puYS7VnG.ndxmn.cn
http://bQfwlpXA.ndxmn.cn
http://ENGWWejN.ndxmn.cn
http://www.dtcms.com/a/379821.html

相关文章:

  • Java生态圈核心组件深度解析:Spring技术栈与分布式系统实战
  • 解决Ubuntu中apt-get -y安装时弹出交互提示的问题
  • 硅基计划3.0 Map类Set类
  • Ubuntu20.04手动安装中文输入法
  • 算法训练营DAY60 第十一章:图论part11
  • java 反射Class类/加载类/创建对象及方法
  • RL【9】:Policy Gradient
  • Java短链接生成服务实战指南
  • JAVA Web —— A / 网页开发基础
  • TensorFlow深度学习实战:从零开始构建你的第一个神经网络
  • Keepalived 负载均衡
  • 智能文档处理业务,应该选择大模型还是OCR专用小模型?
  • 《Redis核心机制解析》
  • Netty 在 API 网关中的应用篇(请求转发、限流、路由、负载均衡)
  • 金蝶云星空插件开发记录(一)
  • Knockout-ES5 入门教程
  • 基于 Art_DAQ、InfluxDB 和 PyQt 的传感器数据采集、存储与可视化
  • 【图像处理基石】图像压缩有哪些经典算法?
  • C语言实战:简单易懂通讯录
  • youte-agent部署(windows)
  • Python实现点云法向量各种方向设定
  • Linnux IPC通信和RPC通信实现的方式
  • apache实现LAMP+apache(URL重定向)
  • MongoDB 与 GraphQL 结合:现代 API 开发新范式
  • k8s-临时容器学习
  • uni-app 根据用户不同身份显示不同的tabBar
  • ubuntu18.04安装PCL1.14
  • Ubuntu 系统下 Anaconda 完整安装与环境配置指南(附常见问题解决)
  • 网络链路分析笔记mtr/traceroute
  • 在 Ubuntu 系统中利用 conda 创建虚拟环境安装 sglang 大模型引擎的完整步骤、版本查看方法、启动指令及验证方式