C语言的数据存储详解

C语言数据存储

文章目录

  • C语言数据存储
    • 类型的基本归类
      • 类型的意义
    • 数据在内存中的存储
      • 整形在内存中的存储
        • 大小端
        • 整形提升和截断
      • 浮点型在内存中的存储
        • 浮点型的存储规则
          • E的不同情况
        • 运用

类型的基本归类

有无符号的意义:生活中有写数据是没有符号之分的,将最高位(即符号位)利用可以扩大范围

整形包含类型占用空间备注
charunsigned char1Byte字符的本质是ASCII值,是整形
signed char1Byte不同于直接创建 int a时,a为signed
char1Bytechar 到底是signed 还是 unsigned 标准是未定义的,取决于编译器(VS下为signed)
shortunsigned short (int)2Bytes
(signed) short (int)2Bytes
intunsigned int4Bytes
(signed) int4Bytes
longunsigned long (int)4/8BytesC语言在规定类型大小时,只规定了 sizeof(long) >= sizeof(int)
(signed) long (int)4/8Byteslong 在x86为4,x64为8
long longunsigned long long (int)8Byteslong long 为C99中引入
(signed) long long (int)8Bytes
浮点型占用空间备注
float4Bytesfloat 的精度低,存储范围小,double 精度高,范围大
double8Bytes
long double不定长度可能会应编译器和平台的不同而产生差异,可能和 double 一样长,可能更长(8/12/16Bytes)

long double 在 C99 标准中被引入,用以表示更高精度的浮点数

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

以及不同类型所对应的指针类型、空类型(void)

空类型常用于函数的返回类型(表示无返回)、函数的参数(无需参数)等

类型的意义

  • 不同的类型对应所开辟的内存空间大小不同(内存大小决定使用范围)
  • 程序看待对应内存空间的视角(程序以何种规则读取)

以下程序用于验证整形和浮点型的存取规则不同

#include <stdio.h>int main()
{int n = 9;//开辟4bytesfloat* pFloat = (float*)&n;//把n的地址放到pfloat里面,实际还是指向那整形的4bytesprintf("n的值为:%d\n", n);//9printf("*pFloat的值为:%f\n", *pFloat);//0.000000//这里按照浮点的规则取出数据,结果错误,说明整形和浮点的存储方式不同*pFloat = 9.0;printf("num的值为:%d\n", n);//1,091,567,616printf("*pFloat的值为:%f\n", *pFloat);//9.000000return 0;
}

数据在内存中的存储

整形在内存中的存储

整形表示的范围在limits.h中定义(如果不用到上限和下限的话不用引)

在这里插入图片描述

在这里插入图片描述

程序中整形的二进制表示方式有三种,分别为原码、反码和补码

  • 原码即为整数的二进制表示,对于有符号类型,最高位为符号位,0表示正数,1表示负数
  • 正数的三码相同
  • 负数的反码为原码按位取反(最高位不变),补码为反码加1

以7和-7为例(int)

整形表示方式数据
7原码00000000 00000000 00000000 00000111
反码00000000 00000000 00000000 00000111
补码00000000 00000000 00000000 00000111
-7原码10000000 00000000 00000000 00000111
反码11111111 11111111 11111111 11111000
补码11111111 11111111 11111111 11111001

在计算机系统中,数值一律用补码来表示和存储。通过补码,可以将负数视为正数,将加法和减法统一处理(CPU只有加法器)此外,补码与原码相互转换(补码的补码即为原码),其运算过程是相同的,不需要额外的硬件电路

int main()
{int a = 20;//原、反、补:00000000 00000000 00000000 00010100//    十六进制      00       00       00       14  (0x 00 00 00 14)int b = -10;//最高位为符号位//原:10000000 00000000 00000000 00001010// 0x 80       00        00         0a//反:11111111 11111111 11111111 11110101// 0x ff        ff        ff         f5//补:11111111 11111111 11111111 11110110// 0x ff        ff        ff         f6//对补码取反://      10000000 00000000 00000000 00001001// +1://      10000000 00000000 00000000 00001010 得到原码//20-10 = 20 + (-10)int c = a + b;//00000000 00000000 00000000 00010100//11111111 11111111 11111111 11110110//相加得到一个补码://(1)00000000 00000000 00000000 00001010 最高位被丢掉//0x 00 00 00 0a  (10)return 0;
}
大小端

大小端即计算机系统中两种不同的数据存储方式

大端存储模式 将数据的低位保存在内存中的高位地址,将数据的高位保存在低位地址

小端存储模式 将数据的低位保存在内存中的低位地址,将数据的高位保存在高位地址

由于数据长度、寄存器大小不同,且计算机的存储是以字节为单位的,这就导致了不同长短的数据和寄存器(如16位、32位)之间存在数据存放的顺序问题(即哪些数据放在高地址,哪些放在低地址),大小端存储模式就是为了解决这类问题

我们常用的X86(x64) 结构是小端模式

这里以上面这段简单的代码为例,以下分别位a,b在内存中的存储

在这里插入图片描述

在这里插入图片描述

实际上,数据存储的规则可以是多种的,只要保证存入和取出的方式相同即可

浮点型同样有大小端,但对一个字节的数据,没有顺序可谈

//判断当前环境是大端还是小端
#include <stdio.h>
int check()
{int i = 1;return (*(char*)&i);//将地址强制转为char*,即只读取最低位的数据//当为小端,得到1;当为大端,得到0
}
int main()
{int ret = check();if (ret == 1){printf("小端\n");}else{ printf("大端\n");}return 0;
}
整形提升和截断

截断发生在数据存储时,整形提升发生在使用时

有关整形提升和截断的内容,详见另一篇博客

C语言对类型的转换-CSDN博客

#include <stdio.h>
int main()
{char a = -1;//char 在VS下是有符号的// -1 是整形,为32位,要存入char,要发生截断//原:10000000 00000000 00000000 00000001//反:11111111 11111111 11111111 11111110//补:11111111 11111111 11111111 11111111//发生截断// a -- 11111111// %d 打印有符号整形,发生整形提升,对于有符号数,高位补1// 11111111 11111111 11111111 11111111 -- 补码// 10000000 00000000 00000000 00000000 -- 取反// 10000000 00000000 00000000 00000001 -- +1 得到原码// b的打印同理// 截断和大小端无关,相当于是从内存中拿出数据后再发生截断signed char b = -1;unsigned char c = -1;//原:10000000 00000000 00000000 00000000//反:11111111 11111111 11111111 11111110//补:11111111 11111111 11111111 11111111// c -- 11111111//无符号数高位补0// 00000000 00000000 00000000 11111111 --- 直接就是原码printf("a=%d,b=%d,c=%d", a, b, c);//VS环境下打印  a=-1,b=-1,c=255return 0;
}

浮点型在内存中的存储

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

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

(-1)^s — 符号位,当s=0,V为正数;当s=1,V为负数

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

2^E — 指数位

6.0的二进制表示就是 110.0

s=0,M=1.1,E=2

即为1.1×2^2

6.5就是110.1

s=0, M=1.101,E=2

即为1.101×2^2

浮点型的存储规则

float - 4bytes - 32 bit

最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M

double - 8bytes - 64bit

最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M

根据十进制转换二进制的计算规则(小数部分×2取整,得0为止)可知,当一个数的小数部分在多次乘法取整后仍不为0时,可能会将有效数字所占长度全部使用,后面的数据将无法存储。即浮点数存在丢失精度的情况

IEEE 754规定,在计算机内部保存M时,默认的第一位总是1,因此可以被舍去,只保存后面的小数部分(即保留24/53位有效数字),由此可以提高精度

E为一个无符号整数(unsigned int),当8为8位时,其范围为0~255,而科学计数法中的指数可以存在负数,因此IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,即加上127/1023

E的不同情况
  • E不全为0或不全为1

    此时,E的真实值计算即为(E-中间值)

  • E全为0

    E+127 = 0,这时,浮点数的指数E等于1-127(或者1-1023)即为真实值

    有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于

    0的很小的数字

  • E全为1

    E + 127 = 255

    这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)即 1.xxxxxx * 2^128


运用

利用这些规则,分析上面的代码

#include <stdio.h>int main()
{int n = 9;//00000000 00000000 00000000 00001001//0 00000000 00000000000000000001001//s=0 E=00000000float* pFloat = (float*)&n;printf("n的值为:%d\n", n);//9printf("*pFloat的值为:%f\n", *pFloat);//0.000000//0 00000000 0000000000 0000000001 001//s=0 E=00000000//一个接近0的很小的数*pFloat = 9.0;//9.0 --- 1001.0//s=0 E=3 --- 00000011// 3 + 127 = 130 --- 1000 0010//0 10000010 0010000000 0000000000 000printf("num的值为:%d\n", n);//1,091,567,616//01000001 00010000 00000000 00000000printf("*pFloat的值为:%f\n", *pFloat);//9.000000return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/501129.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线程安全的队列

学习一下别人写的&#xff0c;线程安全的队列代码。https://github.com/markparticle/WebServer/blob/master/code/log/blockqueue.hhttps://github.com/markparticle/WebServer/blob/master/code/log/blockqueue.h /** Author : mark* Date : 2020-06-16* copy…

2024 2.24~3.1 周报

目录 一、本周计划 二、DD-Net整体介绍 三、DDNet的体系结构 四、损失函数 五、课程学习 六、实验环境 A. SEG盐数据集 B. OpenFWI数据集 C. 训练和前沿设置&#xff08;未完&#xff09; 七、结论 八、跑代码——对比试验结果&#xff08;CBAM&#xff09; 1. In…

el-table实现日期表头+二级表头+嵌套echarts

先上效果图 表头的时间首个是搜索项的endTime&#xff0c;后面的时间则是startTime到endTime-1的正序排列&#xff0c;折线图则是时间的正序排列 1、先实现月份表头&#xff0c;用的是项目封装后的el-table&#xff0c;但是跟直接在页面上实现没有啥区别 //数据结构 {"…

css背景图片属性

基础代码&#xff1a; div {width: 200px;height: 200px;background: url(./css-logo.png); }<div></div> 1、background-repeat&#xff1a;默认是repeat 设置背景图片在容器内是否平铺。 background-repeat: repeat-y; background-repeat: repeat-x; background…

MySQL Strict Mode is not set for database connection ‘default‘

在使用 DJango 框架执行迁移文件的命令时&#xff0c;可以看到出现如下警告&#xff1a; (ll_env) D:\workspace\workspace-mengll\learning-log>python manage.py migrate System check identified some issues: WARNINGS: ?: (mysql.W002) MySQL Strict Mode is not set …

Linux——进程控制(一)进程的创建与退出

目录 一、进程创建 1.写时拷贝 2.创建多个进程 二、进程终止 1.main函数的返回值 2.bash中的$? 3.自定义退出码 4.C语言的错误码 5.错误码与退出码的区别 6.代码异常终止 7.exit函数 8.总结 一、进程创建 在之前&#xff0c;我们学过linux中的非常重要的函数——…

人工智能_大模型010_Centos7.9中CPU安装ChatGLM3-6B大模型_安装使用_010---人工智能工作笔记0145

从一个空的虚拟机开始安装: https://www.modelscope.cn/models/ZhipuAI/chatglm3-6b/files 可以看到这里有很多的数据文件,那么这里 这里点击模型文件就可以下载,这个就是chatglm3-6B的文件,需要点击每个文件,然后点击右边的下载,把文件都下载下来 右侧有下载按钮.点击下载可…

android TextView 实现富文本显示

android TextView 实现富文本显示&#xff0c;实现抖音直播间公屏消息案例 使用&#xff1a; val tvContent: TextView helper.getView(R.id.tvContent)//自己根据UI业务要求&#xff0c;可以控制 图标显示 大小val levelLabel MyImgLabel( bitmap 自己业务上的bitmap )va…

阿里云中小企业扶持权益,助力企业开启智能时代创业新范式

在数字化浪潮的推动下&#xff0c;中小企业正面临着转型升级的重要关口。阿里云深知中小企业的挑战与机遇&#xff0c;特别推出了一系列中小企业扶持权益&#xff0c;旨在帮助企业以更低的成本、更高的效率拥抱云计算&#xff0c;开启智能时代创业的新范式。 一、企业上云权益…

GEE必须会教程—影像数据的区间赋值、插值与比较筛选

影像数据的操作方法比较多&#xff0c;学到今天&#xff0c;至少我们已经学会了如何定义一个影像&#xff0c;以及如何利用Image封装的函数方法进行操作。接下来&#xff0c;我们继续看Image的影像操作方法。 A.定义波段的数据格式 在编程语言中&#xff0c;我们需要根据数据…

新王炸:文生视频Sora模型发布,能否引爆AI芯片热潮

前言 前方高能预警&#xff0c;Sora来袭&#xff01; 浅析Sora的技术亮点 语言模型中构建关键词联系 视频素材分解为时空碎片 扩散模型DiT Not for play, But change world! OpenAI的宏大目标 未来已来&#xff0c;只是尚未流行 Sora的成本与OpenAI的7万亿美金豪赌 算…

【Java设计模式】二、单例模式

文章目录 0、单例模式1、饿汉式2、懒汉式3、双重检查4、静态内部类5、枚举6、单例模式的破坏&#xff1a;序列化和反序列化7、单例模式的破坏&#xff1a;反射8、单例模式的实际应用 设计模式即总结出来的一些最佳实现。GoF(四人组) 书中提到23种设计模式&#xff0c;可分为三大…