数据的存储(c语言)

数据类型

1.整型家族

char(字符的本质是ASCII码值,是整型), short, int, long, long long

(取值范围在<limits.h>中定义)

2.浮点数家族

float, double, long double

(取值范围在<float.h>中定义)

3.构造类型
>数组类型

例如:int arr[5]的类型为int [5]

>结构体类型 struct
>枚举类型 enum
>联合类型 union
4.指针类型

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

5.空类型

void表示空类型(无类型)

大小端字节序

字节序:以字节为单位来讨论顺序

大端字节序存储

把一个数据的高位字节序的内容存放在低地址处,把低位字节序的内容放在高地址处,就是大端字节序存储。

小端字节序存储

把一个数据的高位字节序的内容存放在高地址处,把低位字节序的内容放在低地址处,就是小端字节序存储。

如何确定大/小端字节序存储

int a=1       即00000000 00000000 00000000 00000001

转十六进制:0x 00  00  00  01

以*(char*)&a的方式判断内存存储的第一个字节是00还是01,以此确定大端或小端

这也就是为什么VS编译器中内存存储数据顺序相反的原因,因为采取的是小端字节序存储

整型的存储

一、存储结构与编码方式

1.符号位与数值位

有符号整型(如 int、short)的最高位为符号位(0表示正,1表示负),其余为数值位;无符号整型(如 unsigned int)则全为数值位。例如,int 通常占用4字节(32位),符号位占1位,数值位占31位。

2.补码存储

所有整型数据在内存中均以补码形式存储。补码的生成规则如下:
正数:补码与原码相同。
负数:原码符号位保留,数值位按位取反后加1。
例如,int a = -7 的补码为 11111111 11111111 11111111 11111001,对应十六进制 ffffff9。

3.补码的意义

补码设计解决了以下问题:
统一加减法运算:CPU仅需加法器即可完成加减操作(如 60 + (-18) 的补码运算结果正确)。
消除正负零的歧义:反码存在两种零,而补码仅一种零(0000 0000)。

二、存储空间与数值范围

1.常见整型的存储大小

short:2字节(16位),范围 -32768 到 32767(有符号)或 0 到 65535(无符号)。
int:4字节(32位),范围 -2^31 到 2^31-1(有符号)或 0 到 2^32-1(无符号)。
long:通常4字节(32位),部分系统为8字节(64位)。

2.溢出行为

当数值超出范围时,整型会循环溢出。例如:
int 最大值加1会变为最小值(如 2147483647 + 1 = -2147483648)。
short 最小值减1会变为最大值(如 -32768 - 1 = 32767)。

三、字节序(大小端模式)

1.定义

大端模式:高字节存储在低地址,低字节存储在高地址。
小端模式:低字节存储在低地址,高字节存储在高地址。
例如,32位整数 0x12345678:
大端存储为 12 34 56 78,小端存储为 78 56 34 12。

2.判断字节序

可通过以下代码判断当前系统字节序:

int check { int i = 1; return *(char*)&i; }  // 返回1为小端,0为大端

四、无符号与有符号的转换

隐式转换规则

无符号类型可直接赋值给有符号类型,但可能因符号位冲突导致负值。
有符号负数赋值给无符号类型时,会通过补码转换为正值(如 -1 转换为 255)。
示例
signed char a = -1;   // 二进制:11111111(补码)
unsigned char b = a;  // 转换为无符号后,值为255

五.无符号类型存储负数

举例:(存储并打印)

因为是char,所以截断 ,只取最后8位

c为1111 1111

因为打印类型是%d,所以整型提升

由于是unsigned char,所以整型提升高位补0

所以输出的c为00000000 00000000 00000000 11111111(正数原码,反码,补码相同) 

知识点(个人理解,可能有误):1.整型提升是按数据类型,而不是按照打印类型 

 2.变量存储的是补码,而打印类型是根据补码去打印原码 

3.计算机中存储与计算都是以补码进行的,(两数相加,结果的符号位由两数绝对值的大小关系决定) 

浮点型在内存中的存储


浮点型数据在内存中的存储遵循 IEEE 754 标准,其核心是将数值分解为符号、指数和尾数三部分,通过二进制科学计数法表示。

根据国际标准IEEE 754,任意一个二进制浮点数V可以表示为下面的形式

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

(-1)^S表示符号位,当S=0,V表示正数;当S=1,V为负数

M表示有效数字,大于等于1,小于2

2^E表示指数位

以下是详细解析:


一、浮点数的存储结构

根据IEEE 754标准,浮点数分为**单精度(32位)和双精度(64位)**两种格式:

1.单精度(float)

符号位(1位):0表示正数,1表示负数。
指数位(8位):存储偏移后的指数值(偏移量为127),实际指数为 存储值 - 127。
尾数位(23位):存储规范化后的有效数字(小数点后部分),隐含小数点前的1(即实际尾数为 1.尾数位)。

2.双精度(double)

符号位(1位):与单精度相同。
指数位(11位):偏移量为1023,实际指数为 存储值 - 1023。
尾数位(52位):同样隐含小数点前的1。

二、存储过程示例

以单精度浮点数 3.14 为例,解析其存储步骤:

1.十进制转二进制

整数部分:3 → 11
小数部分:0.14 → 0.0010001111010111000010...(乘2取整法)
合并后:11.0010001111010111000010... × 2^0。

2.规范化

移动小数点使整数部分为1:1.10010001111010111000010... × 2^1。

3.处理指数与尾数

指数:1 + 127 = 128 → 二进制 10000000。
尾数:舍去隐含的1,取小数点后23位:10010001111010111000010,补零至23位。

4.组合存储

最终二进制表示:0 10000000 10010001111010111000010,对应十六进制 0x4048F5C3。


三、特殊值的处理

1.零与接近零的数

指数全0时,尾数为0表示0;尾数非0表示接近0的极小值(如 ±1.0×2^{-126})。

2.无穷大与NaN(非数值)

指数全1时,尾数全0表示无穷大(符号位决定正负);尾数非0表示NaN。

3.溢出与下溢

指数超出范围时,结果为无穷大或0,具体取决于数值大小。


四、存储模式与精度问题


1.精度限制

单精度尾数仅23位,无法精确表示所有十进制小数(如0.1),导致舍入误差。

2.字节序影响

小端模式:低字节存于低地址(如x86架构)。
大端模式:高字节存于低地址(如ARM默认模式)。
例如,32位数据 0x12345678 在小端模式下存储为 0x78 0x56 0x34 0x12。

五、验证存储的示例代码


通过强制类型转换和指针访问内存,可验证浮点数的存储形式:

float f = 3.14;
unsigned char *p = (unsigned char*)&f;
for (int i = 0; i < 4; i++) {
    printf("%02X ", p[i]); // 输出十六进制字节序列
}
输出结果:C3 F5 48 40(小端模式下),对应十六进制 0x4048F5C3。


六.总结


浮点数的存储本质是通过符号、指数偏移和尾数隐含规则,将十进制数转换为二进制科学计数法。其精度限制和字节序特性对编程中的数值计算和内存操作有重要影响。

七.额外的

为什么浮点数在计算机中存储不精确?

举例:v=9.5f     二进制表示为1001.1

已知整数部分分别表示1*2^3, 0*2^2, 0*2^1, 1*2^0

小数部分表示1*2^-1,以此类推之后的数位依次*2^-2, *2^-3等

小数位这样的存储方式,而且存储位数有限,就导致浮点数存储可能不精确

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值