C语言--数据的存储2
目录
- 前言
- 练习
- 有符号类型与无符号类型
- char类型的取值范围
- 有符号char
- 无符号char
- 有符号与无符号类型混合运算
- 有符号无符号类型形成的bug
- char类型取值范围应用
- 浮点型在内存中的存储
- 浮点数的存储
- 浮点数存储规则
- 浮点数取出规则
前言
上篇文章我们讲解了数据类型,类型的基本归类,整形在内存中的存储方式以及大小端的知识,本篇文章我们来继续加深数据在内存中存储形式的理解。
练习
有符号类型与无符号类型
我们来看一个例子,看下面这段代码输出是什么:
#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
我们先来分析a
char a=-1
10000000000000000000000000000001 --原码
11111111111111111111111111111110 --反码
11111111111111111111111111111111 --补码
11111111 --char类型只能存储1个字节(8个比特位)
b,c和a的补码其实一样,都是11111111,只不过一个是有符号的char,一个是无符号的char。
所以对于b来说,第一个1是符号位,而对于c来说,这8个1全都是有效数字。
因为我们要以%d的形式打印,所以要对a,b,c进行整形提升,
a:11111111
整形提升:11111111111111111111111111111111 --补码11111111111111111111111111111110 --反码10000000000000000000000000000001 --原码
所以a打印出来还是-1。
b与a类似,只是添加了一个有符号前缀,效果是一样的。我们来分析c
c:11111111
整形提升:00000000000000000000000011111111 --补码(原码)
因为符号位为0,所以原反补码相同,所以c打印出来就是11111111==255。
补充:
1,char到底是signed char还是unsigned char?
C语言标准没有明确的规定,取决于编译器
2,int 是默认 signed int
char类型的取值范围
有符号char
来看下面这段代码
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
运行结果如图2
为什么会出现这样一个奇怪的数字呢?我们来分析一下
char a=-128
1000000000000000000000010000000 --原码
1111111111111111111111101111111 --反码
1111111111111111111111110000000 --补码
10000000 --截断
1111111111111111111111110000000 --整形提升(补码)
因为%u是打印无符号整数,所以编译器会把整型提升后的补码全部当作有效数字,那么原反补码相同,打印的就是补码。如果是打印%d,就还需要求出原码。
我们接着再来看下面这段代码
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
代码运行结果如图3
char a=-128
0000000000000000000000010000000 --原码
0111111111111111111111101111111 --反码
1111111111111111111111110000000 --补码
10000000 --截断
1111111111111111111111110000000 --整形提升(补码)
我们发现,截断以后的值和-128是一样的,所以最终结果也相同。
我们通过图中分析可知,有符号char类型的取值范围为-128~127,为什么没有128呢
我们再来看一个图
我们发现127再加1,即01111111加1变为10000000,会被直接解读为-128,所以放128进去会被解读成一个负数。
无符号char
如图6
和无符号不同的是,最高位也被当作有效数字计算,所以无符号char取值范围为0~255。
有符号与无符号类型混合运算
我们还是来看下面这段代码
int main()
{int i = -20;unsigned int j = 10;printf("%d\n", i + j);return 0;
}
运行结果如图7
为什么会得到这样一个结果呢?我们还是来从原反补码方向分析
int i=-20
100000000000000000010100 --原码
111111111111111111101011 --反码
111111111111111111101100 --补码
unsigned int j=10
000000000000000000001010 --原码=反码=补码
printf("%d\n", i + j)
111111111111111111101100+000000000000000000001010
=11111111111111111111111111110110 --补码11111111111111111111111111111101 --反码10000000000000000000000000000010 --原码(-10)
所以打印出来的结果为-10。
有符号无符号类型形成的bug
我们来看下面这段代码
#include <stdio.h>
int main()
{unsigned int i;for(i = 9; i >= 0; i--){printf("%u\n", i);}return 0;
}
最终运行结果是死循环,这是因为无符号整形i的值是恒大于0的,这样i>=o就恒成立了,最终导致陷入死循环。
再来看一段代码
#include <stdio.h>
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
运行结果同样是死循环,因为i是无符号char类型,取值范围为0~255,这样i<=255恒成立,最终也是进入死循环。
char类型取值范围应用
我们来看这段代码
int main()
{char a[1000];int i;for (i = 0; i < 1000; i++){a[i] = -1 - i;}printf("%d", strlen(a));return 0;
}
代码运行结果如图8
我们借助图5来进行分析,来看图9
求字符串长度的strlen在访问到\0停止。而\0的ascll码值为0,即访问到0为止,所以在第一个0出现前一共有128+127=255个元素,所以字符串长度为255。
浮点型在内存中的存储
浮点数家族包括: float、double、long double 类型。
浮点数表示的范围:float.h中定义。
浮点数的存储
int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}
运行结果如图10
我们发现运行结果和我们预期相差甚远,接下来我们来具体分析。
我们首先来看四种情况的产生环境,第一种和第四种分别是以***整形的形式存储,以整形的形式打印,以浮点型的形式存储,以浮点型的形式打印,***所打印出来的结果和我们预期基本相同,而第二种和第三种都是整形和浮点型杂糅在一起存储打印,结果和预期相差甚远,由此可见浮点型存储方式和整形存储方式肯定是有所不同的
所以想弄清楚上述代码如何运行的,我们首先要来了解浮点型的存储方式
浮点数存储规则
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
---->(-1)^S * M * 2^E
---->(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。
---->M表示有效数字,大于等于1,小于2。
---->2^E表示指数位。
我们来对一个浮点数进行转换,如图11
那么S,E,M在内存中具体是怎么储存的呢?
32位机器:
64位机器:
S占一个比特位这个比较好理解,因为S不是0就是1,所以只用一个比特位来存储即可。
而对于M,因为我们知道M是恒大于1小于2的,所以他的形式永远都是1.xxxxxxx…,所以根据IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字,可以多提高一位的精度。
至于指数E,情况就比较复杂。
首先,E为一个无符号整数(unsigned int)
这意味着,如果E为8位,它的取值范围为0 ~ 255,如果为11位,它的取值范围为0 ~ 2047。但是,我们知道,科学计数法中的E是可以出现负数的,
如图14
所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127(比如要存-1,其实要存-1+127=126);对于11位的E,这个中间数是1023。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即
10001001。
我们还是以5.5为例
1010.1 --转换为二进制
101.1=1.011*2^2
S=0 M=1.011 E=2
转换:
S=0 M=011 E=2+127
按32位机器存储
0100 0000 1011 0000 0000 0000 0000 0000
//40 b0 00 00(16进制存储)
浮点数取出规则
指数E从内存中取出可分为三种情况
1,E不全为0或不全为1
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将
有效数字M前加上第一位的1。
比如:
0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为
1.0*2^(-1),其阶码为-1+127=126,表示为
01111110,而尾数1.0去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进
制表示形式为:
0 01111110 00000000000000000000000
2,E全为0
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,
有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于
0的很小的数字
3,E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)
下面我们在来解决一开始的那段代码。
int n = 9;float* pFloat = (float*)&n;printf("*pFloat的值为:%f\n", *pFloat);
*pFloat = 9.0;printf("num的值为:%d\n", n);printf("*pFloat的值为:%f\n", *pFloat);
通过以上分析就可得出编译器中得出的结果
以上就是关于数据的存储的全部内容了,如有出入,欢迎指正。
相关文章:

C语言--数据的存储2
目录前言练习有符号类型与无符号类型char类型的取值范围有符号char无符号char有符号与无符号类型混合运算有符号无符号类型形成的bugchar类型取值范围应用浮点型在内存中的存储浮点数的存储浮点数存储规则浮点数取出规则前言 上篇文章我们讲解了数据类型,类型的基本…...

Ubuntu 安装 Qt5.7.0
下载 地址:https://download.qt.io/https://download.qt.io/ 文件夹说明: snapshots:预览版,该文件夹中包含最新的测试版本。 online:在线安装包。 official_releases:最终发布版。 new_archive&#…...

“世界”的伊利,“三难”的潘刚
(图片来源于网络,侵删) 来源 | 螳螂观察 文 | 叶小安 一棵草,一头牛,到一杯牛奶,乳品如何守住舌尖上的安全? 央视财经频道专访中,伊利集团董事长兼总裁潘自信满满地介绍了现代智…...

【新】华为OD机试 - 开心消消乐(Python)
开心消消乐 题目 给定一个 N 行 M 列的二维矩阵,矩阵中每个位置的数字取值为 0 或 1,矩阵示例如: 1 1 0 0 0 0 0 1 0 0 1 1 1 1 1 1现需要将矩阵中所有的 1 进行反转为 0,规则如下: 当点击一个 1 时,该 1 被反转为 0,同时相邻的上、下、左、右,以及左上、左下、右上…...

山东大学2022-2023数据仓库挖掘期末考题回忆
2023.2.14 一、 1.数据预处理的过程和解决问题 2.什么是离群点,检测离群点的四个方法 3.数据仓库的四个特点,画出数据仓库结构图 4.维度归约的两个方法及区别。 二、 两个模型用来预测新冠病毒的阳性和阴性 1.分别求准确率,精确率,…...

SSM整合
SSM整合 ContextLoaderListener Spring提供了监听器ContextLoaderListener,实现ServletContextListener接口,可监听 ServletContext的状态,在web服务器的启动,读取Spring的配置文件,创建Spring的IOC容器。 web 应用中…...

Android平台版本所对应的 API 级别
平台版本API级别版本号备注Android 1333TIRAMISU平台亮点Android 1232S_V2平台亮点31S平台亮点Android 1130R平台亮点Android 1029Q平台亮点Android 928P平台亮点Android 8.127O_MR1平台亮点Android 8.026O平台亮点Android 7.1.1Android 7.125N_MR1平台亮点Android 7.024N平台亮…...

入职字节外包一个月,我离职了
有一种打工人的羡慕,叫做“大厂”。 真是年少不知大厂香,错把青春插稻秧。 但是,在深圳有一群比大厂员工更庞大的群体,他们顶着大厂的“名”,做着大厂的工作,还可以享受大厂的伙食,却没有大厂…...

中创教育PMP分享,复盘没效果?该怎么办
复盘的清单框架 一、现在情况如何 二、当初是怎么决定的 三、让我们再审视下思考的前提 四、复盘他人 复盘没效果,我们可以试试下面的提问: 一、现在情况如何 现在做到什么程度? 当时定的目标是多少? 现在的结果和目标对比处于什么状态? 有没…...

Kubelet监控指标说明
Probe路径 含义:kubelet以及kubelet监控的Pod的存活性请求路径:“/metrics/probes”指标 名称类型含义upGauge服务是否存活prober_probe_totalCounter按结果计算容器的活动探测、就绪探测或启动探测的累计数目以及存活性结果 Metrics路径 含义&#x…...

python中的数据类型(价值6980的全能工程师课程笔记)
概述 python数据类型主要分为以下七大类: Numbers(数字) Boolean(布尔) String(字符串) List(列表) Tuple(元组) Dictionary(字典) Set(集合) Python 的七个标准数据类型中: 不可变数据类型(4 个):Number(数字)、Boolean(布尔)、String(字符串)、T…...

Tomcat 配置IPV6
文章目录一、场景二、tomcat开启ipv6三、ipv6环境配置四、访问总结一、场景 我们在linux下安装一个tomcat,启用ipv6的方式,然后在windows下用浏览器访问这个tomcat 二、tomcat开启ipv6 在server.xml配置文件的里面加上 address”[::]” ,这…...

JavaEE——MyBatis的简单介绍和使用
MyBatis是什么 MyBatis是一个支持普通SQL查询,存储过程以及高级映射的持久层框架,他消除了几乎所有的JDBC代码和参数的手动设置以及对结果集的检索,使用简单的XML或注解进行配置和原始映射,将接口和Java的POJO映射成数据库中的记…...

主数据管理平台如何进行模型管理
企业管理主数据,模型管理尤为重要。在对主数据进行建模操作时,既要保证数据通用性、安全性,又要符合企业的业务需求。今天小亿带你认识一下亿信华辰睿码主数据管理平台里的主数据模型管理。 主数据模型分类 一款专业的主数据管理平台&#…...

在 Kubernetes 上运行《我的世界》
最近给小朋友装上了叨叨许久的 Minecraft(我的世界),为了体验安装的是开源启动器 HMCL。其实这游戏我也关注比较久了,不过感觉太耗时间。但被小朋友拉上一起玩,便研究了下自建服务器。GitHub 发现已经有人做好了 Minec…...

万字长文掌握Python高并发
文章目录0 前言1 并发、并行、同步、异步、阻塞、非阻塞1.1 并发1.2 并行1.3 同步1.4 异步1.5 阻塞1.6 非阻塞2 多线程2.1 Python线程的创建方式2.1.1 方式一2.1.2 方式二 继承Thread2.1.3 通过线程池创建多线程2.2 聊聊GIL2.2.1 Python线程与操作系统线程的关系2.3 线程同步2.…...

高性能办公娱乐迷你主机——Maxtang大唐AMD5600U
今天给大家介绍一款AMD5600U迷你主机,说起这款处理器大家应该并不陌生,像联想小新、YOGA以及ThinkBook等很多款用的都是这个型号,不过笔记本的价格基本都在3999-4999这个价位区间,同样的处理器,笔记本卖那么贵…...

牛客教你用雇主品牌力抢人才!附6类校招玩法
最新校招数据显示,79%的应届生在Offer抉择时首要考量薪资福利。但谈钱多伤感情啊~牛客从100案例中挑出6种最潮的校招雇主品牌玩法,助力你抢人才。01、英特尔中国:“芯”动小镇雇主是否能让自己产生激情和热情,已经成为应届生选择O…...

leaflet: 鼠标mouseover显示城市信息,mouseout隐藏信息(067)
第067个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中显示城市信息,这里给marker添加鼠标事件,用到了mouseover和mouseout,用于控制信息的显示和隐藏。 直接复制下面的 vue+leaflet源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码…...

docker部署springboot项目
1、创建放置项目jar包和Dockerfile的文件夹 cd usr/ mkdir reggie cd reggie/ 2、上传Dockerfile和项目jar包 Dockerfile内容如下: # 基础镜像使用java FROM java:8 # 作者 MAINTAINER chenxiansheng # VOLUME 指定了临时文件目录为/tmp。 # 其效果是在主机 /v…...

简单实用的CSS属性(滑轮滚动保持头部不动、暂无数据显示、元素隔开距离、带背景的文字效果、网页上禁止选中文字、校验值有效为绿色无效为红色、)
简单实用的CSS属性(滑轮滚动保持头部不动、暂无数据显示、元素隔开距离、带背景的文字效果、网页上禁止选中文字、校验值有效为绿色无效为红色、) 目录 一、滑轮滚动保持头部不动 二、暂无数据显示 三、元素隔开距离 四、带背景的文字效果 backgro…...

Unity 工具 之 SoftMask软遮罩 实现 UI 边缘渐变过渡的简单使用介绍
Unity 工具 之 SoftMask软遮罩 实现 UI 边缘渐变过渡的简单使用介绍 目录 Unity 工具 之 SoftMask软遮罩 实现 UI 边缘渐变过渡的简单使用介绍 一、简单介绍 二、Mask 实现的遮罩效果 三、Soft Mask 实现遮罩效果 四、 Soft Mask 的一些设置 五、插件下载 一、简单介绍 U…...

Python-第六天 Python数据容器
Python-第六天 Python数据容器一、数据容器入门1.数据容器二、数据容器:list(列表)1.列表的定义2.列表的下标(索引)3.列表的常用操作(方法)4.练习案例:常用功能练习5.list(列表)的遍历5.1 列表的…...

【C/C++基础练习题】复习题三,易错点知识点笔记
C复习题知识点记录: 在定义结构体类型时,不可以为成员设置默认值。 在公用一个共用体变量时。系统为其分配存储空间的原则是按成员中占内存空间最大者分配 a ,La, "a", L"a" 字符 长字符 字符串 长字符串 布尔类型只有两个值 fal…...

Mysql sql优化
插入优化 1️⃣ 用批量插入代替单条插入 insert into 表明 values(1, xxx) insert into 表明 values(2, xxx) ... 改为使用👇 insert into 表名 values(1, xxx), (2, xxx)...2️⃣ 手动提交事务 start tranaction; insert into 表名 values(1, xxx), (2, xxx)... in…...

vnode 在 Vue 中的作用
vnode就是 Vue 中的 虚拟 dom 。 vnode 是怎么来的? 就是把 template 中的结构内容,通过 vue template complier 中的 render 函数(使用了 JS 中的 with 语法),来生成 template 中对应的 js 数据结构,举个例…...

SQL语句实现找到一行中数据最大值(greatest)/最小值(least);mysql行转列
今日我在刷题时遇到这样一个题,它提到了以下需求: 有一场节目表演,五名裁判会对节目提供1-10分的打分,节目最终得分为去掉一个最高分和一个最低分后的平均分。 存在以下一张表performence_detail,包含字段有performa…...

记一次以小勃大,紧张刺激的渗透测试(2017年老文)
一、起因 emmm,炎炎夏日到来,这么个桑拿天干什么好呢? 没错,一定要坐在家里,吹着空调,吃着西瓜,然后静静地挖洞。挖洞完叫个外卖,喝着啤酒,撸着烧烤,岂不美…...

LeetCode 61. 旋转链表
原题链接 难度:middle\color{orange}{middle}middle 题目描述 给你一个链表的头节点 headheadhead ,旋转链表,将链表每个节点向右移动 kkk 个位置。 示例 1: 输入:head [1,2,3,4,5], k 2 输出:[4,5,1…...

数据库(4)--视图的定义和使用
一、学习目的 加深对视图的理解,熟练视图的定义、查看、修改等操作 二、实验环境 Windows 11 Sql server2019 三、实验内容 学生(学号,年龄,性别,系名) 课程(课号,课名,…...