【C语言】整,浮点型数据存储,大小端。细节拉满!!

news2024/9/20 22:43:10

目录

一. 整型

1. C语言内置整型家族

类型的意义:

2.整型在内存如何存储的呢?

3.  原码,反码, 补码

原码

反码

补码

4. 当 整型遇上unsigned 会发生什么呢?

1. unsigned 与 signed 解析

2. printf 输出 有无符号数解析

3. 小试牛刀

二. 浮点型

1.  浮点型与整型在存储上的区别

2. 常见的浮点类型

1.  浮点数——存

(1) S区

(2)M区

(3) E区 将会复杂一些

2.  浮点数——取

(1.  E 不全为 1 或 0

(2.  E 全为 1

(3.  E 全为 0

3.  让我们回到浮点型小节开头的题目

三. 数据计算(简述)

四.大小端字节序存储

1.  什么是大小端?

2. 为什么有大端和小端

3. 通过函数判断机器大小端

结语


一. 整型

1. C语言内置整型家族

char 1Byte

int 4Byte或2Byte

long 4个Byte或8Byte

long long 更长整型

类型的意义:

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

2.  如何看待内存空间的视角

2.整型在内存如何存储的呢?

我们知道类型决定了开辟内存的大小,计算机为 a 分配四个字节的空间。 那如何存储?

int a = 10;
int b = -20;

3.  原码,反码, 补码

计算机中所有的数据都是由二进制存储,其中符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方法各不相同。

原码

直接将二进制按照正负数的形式翻译成二进制就可以。

反码

将原码的符号位不变,其他位依次按位取反就可以得到了。

补码

反码+1就得到补码。

***正数的原、反、补码都相同。

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

为什么呢?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理; 同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,操作简单。

(计算机补码相加,若超出类型范围,结果可能由正数变为负数,负数变正数,原因是:

计算机会保留低位,高位保留)。

比如 完成char 类型 1 - 1

...
 char a = 1;
 char b = -1;
printf("%d", a + b);

内部逻辑:先将1转化为补码(原,反,补一样)形式保存到内存中,-1转化为补码存至内存。然后以补码形式完成计算,最后将结果转化回原码,并以有符号整型,输出数据。

4. 当 整型遇上unsigned 会发生什么呢?

1. unsigned 与 signed 解析

这里用char 举例,我们知道char 等价于 signed char, 原码中首位是符号位,当char被unsigned修饰, 首位就不再是符号位,而是可以表示数据了,那么表示正数的个数扩大一倍。

有符号:

无符号:

2. printf 输出 有无符号数解析

#include<stdio.h>

int main()
{
    unsigned int b = -10;
    printf("%u\n", b); // 4294967286
  // 输出时,计算机认定是无符号型,把补码直接解析(正数,原 = 反 = 补码)。
    printf("%d", b);   // -10
  // 输出时,计算机认定是有符号型,先要判断正负,负则需要转化,所以结果为-10。
    return 0;

结果:

3. 小试牛刀

//输出什么?
#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);// 输出是-1,-1,255
    return 0;
}

解析一下结果-1:(char 等价于 unsigned)

结果255的解析:

逻辑总结:

首先将数据转为补码,然后给变量,如果输出以更大位输出,这是需要位提升(这个取决于保存的类型和输出形式)。


二. 浮点型

1.  浮点型与整型在存储上的区别

  1. 浮点型没有整型的原码,反码,补码概念
  2. 浮点型对数据进行分区存储。

2. 常见的浮点类型

float             // 单精度

double         // 双精度

long double    

当我们需要知道浮点型范围我们可以,调用头文件 float.h (整型范围在 limits.h头文件中)

关于浮点型存储,先让一个例子开头:

int main() 
{ 
 int n = 9; 
 float *pFloat = (float *)&n; 
 printf("n的值为:%d\n",n);  //      结果: 9
 printf("*pFloat的值为:%f\n",*pFloat);//  0.000000

 *pFloat = 9.0; 
 printf("num的值为:%d\n",n);          //  1091567616
 printf("*pFloat的值为:%f\n",*pFloat);//  9.000000
 return 0; 
}

不知道大家是否答对?下面让我们了解浮点型存储方式

1.  浮点数——存

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

  1. (-1)^S * M * 2^E
  2. (-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
  3. M表示有效数字,大于等于1,小于2。
  4. 2^E表示指数位。

举例来说:

  1. 十进制的5.0,写成二进制是 101.0 ,相当于 1.01×2^2 。 那么,按照上面V的格式,可以得出S=0,M=1.01,E=2。
  2. 十进制的-5.0,写成二进制是 -101.0 ,相当于 -1.01×2^2 。那么,S=1,M=1.01,E=2

对于float的32位类型,存储图如下

double的64位,图如下:

(1) S区

存储符号位 (-1)^ S,如 1.3,-1.0,所以最S分别是 0, 1。

(2)M区

我们知道根据IEEE的规定,浮点数转为二进制后,1<M<2,将会化为1.XXXXXX类型,于是科学家们决定不保存1,只保存.XXXXXXX,如:101.1->1.011* 2^2,M保存.011,这样提高了数据的精度,可以保存24位,53位的有效数字。 

(3) E区 将会复杂一些

E区存储为无符号整型(unsigned int),这意味8位的范围是0~255, 11位范围是 0~ 2047,但我们知道E也存在负数形式,那怎么保存呢? IEEE规定E原始数需要加上一个中间数再保存,8位E,加上127;11位的E加上1023,如:10 + 127 = 137,E = 1000 1001。

2.  浮点数——取

(1.  E 不全为 1 或 0

这时,浮点数就采用下面的规则表示,即

  1. 指数E的计算值减去127(或1023),得到真实值。
  2. 再将有效数字M前加上第一位的1。

比如: 0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为1.0*2^(-1),其阶码为-1+127=126,E表示为01111110,S 为 0,M为00000000000000000000000 ,则其二进制表示形式为:

0 01111110 00000000000000000000000

(2.  E 全为 1

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

(3.  E 全为 0

这时,浮点数的指数E等于1-127 (或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。

3.  让我们回到浮点型小节开头的题目

int main() 
{ 
 int n = 9; 
 float *pFloat = (float *)&n; 
 printf("n的值为:%d\n",n);  //      结果: 9
 printf("*pFloat的值为:%f\n",*pFloat);//  0.000000

 *pFloat = 9.0; 
 printf("num的值为:%d\n",n);          //  1091567616
 printf("*pFloat的值为:%f\n",*pFloat);//  9.000000
 return 0; 
}

解析如下

int main()
{
    int n = 9;
    float* pFloat = (float*)&n;
    printf("n的值为:%d\n", n);  //      结果: 9
    // 整型补码  0000 0000 0000 0000 0000 0000 0000 1001
    printf("*pFloat的值为:%f\n", *pFloat);//  0.000000
    // 以浮点型存储视角来看
    // 0 00000000 00000000000000000001001
    //->  (-1)^(0) * 0.00000000000000000001001 * 2 *(-126)

    *pFloat = 9.0;
    // 9.0二进制 1001.0->  S = 0, E = 3, M = .001
    // 所以其浮点数二进制为 0 10000010 00100000000000000000000  然后给 n 
    printf("num的值为:%d\n", n);          //  1091567616
    // 将n内的数据以有符号整型输出(说白了就是以整型输出法则输出数据)
    // 所以就是这么大的数
    printf("*pFloat的值为:%f\n", *pFloat);//  9.000000
    // 数据本身是以浮点型存储,然后以浮点型方式取出,E = 130 - 127,M 的头添上个一
    // (-1)^(0) * (1.001) * 2^(3) 所以结果为 9.000000(float类型默认保存小数点后6位)
    return 0;
}

结论:计算机整型数据以 浮点型输出可能会发生错误,浮点型数据 以 整型数据输出也会发生错误。

三. 数据计算(简述)

但,你存储跟我计算有毛子事?!

计算机在对待不同数据类型时,会首先将数据自动转化,保证数据为同一类型,再进行计算,由于只是完成本次运算,因此转化只是临时数据(强制转化也是),不改变原始数据类型;

计算机为了保证数据精度,所以只会由低位向高位自动转化,如图:

可以自动进行的类型转换一般风险较低,不会对程序带来严重的后果,例如,int 到 double 没有什么缺点,float 到 int 顶多是数值失真。只能强制进行的类型转换一般风险较高,或者行为匪夷所思,

例如,char * 到 int * 就是很奇怪的一种转换,这会导致取得的值也很奇怪,再如,int 到 char * 就是风险极高的一种转换,一般会导致程序崩溃。(一般验证某些算法,内存调试)

使用强制类型转换时,程序员自己要意识到潜在的风险。

关于数据计算这里不做太多讲解。

四.大小端字节序存储

1.  什么是大小端?

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;

小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。

不多说上图:

2. 为什么有大端和小端

为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为高字节, 0x22为低字节。

大端模式:    就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。

小端模式:    刚好相反。我们常用的 X86 结构是小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式

3. 通过函数判断机器大小端

思路:通过取的第一个字节的内容,如果为1则为小端,为0则为大端。

#include<stdio.h>
int main()
{
    int a = 1;
    if (*(char *)&a) // char类型占一个字节,将a地址抢转为char类型指针,
//然后解引用得出里面的值要么为1,要么为0.
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}

让我们看内存中的前4列,机器确实是小端。(机器方便展示,将二进制转化为16进制的数)

结语

本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论;如果给小伙伴带来一些收获请留下你的小赞,你的点赞和关注将会成为博主创作的动力。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kafka学习---1、Kafka 概述、Kafka快速入门

1、Kafka概述 1.1 定义 1、Kafka传统定义&#xff1a;Kafka是一个分布式的基于发布/订阅模式的消息队列(Message Queue)&#xff0c;主要是应用于大数据实时处理领域。 2、发布/订阅&#xff1a;消息的发布者不会将信息直接发送给特定的订阅者&#xff0c;而是将发布的信息分…

【Linux 学习 ①】- Linux 环境搭建

目录 一、GouMai 云服务器 二、使用 Xshell 远程登录服务器 三、编写一个 C 程序 四、多用户共享同一个服务器 一、GouMai 云服务器 我们以腾讯云为例&#xff08;购买其他厂商的云服务器&#xff0c;例如&#xff1a;华为云、阿里云&#xff0c;其操作也是类似的&#…

Java集成开发环选择与Eclipse初始常用配置

开发工具的选择 Eclipse 、Idea是最常用的两个Java开发工具&#xff0c;虽然Idea相比前者更易用&#xff0c;但由于其价格昂贵&#xff0c;且由于整体市场经济环境的猥琐&#xff0c;导致各公司开始打击盗版软件&#xff0c;以此来增加收入。 基于以上背景&#xff0c;还是建议…

Kamrada operator:新一代的 Karmada 管理方式

Karmada operator 是 Karmada 社区推出的新组件&#xff0c;它为用户提供了全新的 Karmada 生命周期管理的方式。用户可以在全局集群之上集中式来管理多个 Karmada&#xff0c;通过 CR 资源来控制 Karmada 的创建、升级和卸载。为用户运维和管理 Karmada 提供了极大的便捷。本文…

12个经典性能测试人员面试题

1、性能测试包含了哪些软件测试&#xff08;至少举出3种&#xff09;&#xff1f; 参考答案&#xff1a;负载测试;压力测试;容量测试;负载测试&#xff08;Load Testing&#xff09;&#xff1a;负载测试是一种主要为了测试软件系统是否达到需求文档设计的目标&#xff0c;譬如…

如何在 Jupyter Notebook 用一行代码启动 Milvus?

随着各种大语言模型&#xff08;LLM&#xff09;的涌现和 AI 技术变得越来越普遍&#xff0c;大家对于向量数据库的需求也变得越来越多。作为大模型的记忆体&#xff0c;向量数据库不仅可以帮助解决 LLM 面临的最大问题——缺乏特定领域知识和最新数据&#xff0c;还可以赋能相…

【数据结构】查找(一)

因为时间关系&#xff08;现阶段来不及&#xff09;&#xff0c;先不学红黑树和B树&#xff0c;所以这是查找&#xff08;一&#xff09;。 先写一下二分查找&#xff0c;数据结构数上叫的“折半查找”。 二分查找 左闭右闭区间 左闭右开区间 下面依旧是对王道书上选择题的一…

突破竞争壁垒:独立站如何实现有效的品牌差异化?

在当今竞争激烈的电商市场中&#xff0c;独立站已经成为了越来越多品牌的选择。然而&#xff0c;要想在这个竞争激烈的环境中脱颖而出&#xff0c;建立起独特的品牌差异化是至关重要的。品牌差异化是一种战略方法&#xff0c;旨在突出品牌在市场上的独特性和独有价值&#xff0…

Java阶段四Day02

Java阶段四Day02 文章目录 Java阶段四Day02VueCli嵌套路由总结项目开发开发流程关于项目项目分析数据库的设计规范(基于阿里巴巴Java开发手册)数据库表设计创建项目关于依赖项关于<build>报错 VueCli嵌套路由 由于Vue Cli工程是单页面的&#xff0c;为了保证能显示各式各…

如何实现不同服务器之间 大规模数据同步?

随着企业结构分散化的不断扩大&#xff0c;企业的数据中心、服务器节点、异地分支机构之间&#xff0c;会存在多种文件交换场景。传统的FTP、rsync、网盘等传输方式在数据体量较小、时效性要求不高的情况下&#xff0c;基本也可以满足需求。 但随着数量爆发式增长&#xff0c;需…

大二下学期期末总结

文章目录 针对学习方面大学生就业指导与创业教育数据结构Java企业级开发大数据实时处理大数据可视化服务器技术 针对生活方面针对课外活动方面 针对学习方面 大学生就业指导与创业教育 这门课很好的帮我们分析了目前的就业形势&#xff0c;预测了未来的就业前景&#xff0c;为…

庆祝牛学长4周年!精彩折扣活动等你来享!

值此周年庆之际&#xff0c;我们衷心感谢您对我们的支持与信任。为了回馈广大用户的厚爱&#xff0c;我们特别推出一系列令人振奋的打折活动&#xff0c;让您在软件购买和使用过程中获得更多实惠和便利。 活动时间&#xff1a;从即日起&#xff0c;至2023年6月26日 活动链接&…

接口测试开发之:一篇搞懂 Cache、Cookie及Session。

目录 1、引言 2、Cache 2.1 缓存定义 2.1.1 缓存概念 2.1.2 缓存优点 2.2 浏览器缓存 2.2.1 存储路径 2.2.2 缓存优点 2.2.3 缓存弊端 2.2.4 原理图 2.3 代理缓存 2.3.1 原理 2.3.2 应用场景 2.3.3 原理图 2.4 网关缓存 2.4.1 原理 2.4.2 缓存分类 2.4.3 缓存…

uniapp uview2.0 其中u--textarea组件无法换行,换行无效问题解决方案

最终发现是因为默认值的问题&#xff0c;uniapp和uview的官方文档写的confirmType的默认值都是done&#xff0c;但是uniapp的textarea在没有配置的情况下是没有值的&#xff0c;uview给加了一个默认值done&#xff0c;就出现了无法返回的问题&#xff0c;尝试了将uview的textar…

qt样式表qss选择器

目录 1、通用选择器 2、类型选择器&#xff08;类和子类&#xff09; 3、类选择器 4、ID选择器 5、子孙后代控件选择器 6、子后代控件选择器 7、属性选择器 7.1 静态属性 7.2 动态属性 8、子控件选择 9、伪状态选择 在开始之前&#xff0c;先要区分3个概念&#xff1…

Android MediaPlayer多次Seek产生杂音优化

前言 MediaPlayer 作为Android自带的Player目前还是存在很多不好使用问题&#xff0c;但实际开发中&#xff0c;还是有不少使用场景&#xff0c;本文针对多次seek产生杂音的问题进行分析讨论&#xff0c;自己遇到了进行记录&#xff0c;目前底层也不好解决和轻易改动原生代码&…

2020年CSP-J认证 CCF非专业级别软件能力认证第一轮真题-单项选择题解析

2020 CCF认证第一轮&#xff08;CSP-J&#xff09;真题 一、单项选择题 (共15题&#xff0c;每2分&#xff0c;共30分;每题有且有一个正确选项&#xff09; 1、在内存储器中每个存储单元都被赋予一个唯一的序号,称为 A、下标 B、序号 C、地址 D、编号 答案&#xff1a;C…

当618成“抢人大战”,知道“怎么抢”才能“抢得到”

文 | 螳螂观察 作者 | 易不二 今年618对很多平台来说都意义非凡。 尤其是最具主场优势的阿里、京东而言&#xff0c;更是一场硬仗&#xff1a;阿里“16N”组织架构调整后&#xff0c;淘天的第一次大促&#xff0c;且还恰逢也淘宝20周年&#xff1b;京东换帅、CEO许冉第一次接…

华为OD机试真题 Java 实现【素数伴侣】【2023 B卷 100分】,附详细解题思路

一、题目描述 若两个正整数的和为素数&#xff0c;则这两个正整数称之为“素数伴侣”&#xff0c;如2和5、6和13&#xff0c;它们能应用于通信加密。现在密码学会请你设计一个程序&#xff0c;从已有的 N &#xff08; N 为偶数&#xff09;个正整数中挑选出若干对组成“素数伴…

13.常用类|Java学习笔记

文章目录 包装类包装类型和String类型的相互转换Integer类和Character类的常用方法Integer创建机制&面试题 String类创建String对象的两种方式和区别字符串的特性String类的常用方法 StringBuffer类String和StringBuffer相互转换StringBuffer常用方法 StringBuilder类Strin…