C语言深入知识——(1)整形数据和浮点数据的存储

news2024/10/7 20:26:36

1、数据类型的介绍

  • 类型的意义:
    • 使用对应类型能开辟对应内存空间的大小(使用范围)
    • 还有C语言对待不同类型,会采用不同的内存空间视角来看待一个数据
  • C语言中类型的基本归类:
    • 整型(内置类型)
    • 浮点型(内置类型)
    • 空类型(void)
    • 指针型
    • 构造型
      • 数组类型
      • 结构体类型struct
      • 枚举类型enum
      • 联合类型union

2、整型在内存中的存储

(1)原码、反码、补码

①原码的概念

将整数表示为一个二进制数(注意负数最前面的符号位为1),即可得到原码

②反码的概念

原码的符号位不变,其他位0->1,1->0,即可得到反码

③补码的概念

在反码的二进制数基础上+1,即可得到补码

  • 三种表示方法均有符号位和数值位之分
  • 其中符号位0表示“正”,1表示“负”
  • 正整数的原、反、补码相同;负整数的原、反、补码不同
  • 先对原码进行反码再补码<=>先对原码进行补码再反码

④整型以补码的形式存储在内存中

  • 在计算机中,整数类型数值统一用补码表示和存储,原因在于可以将符号位和数值位统一处理
  • 加法和减法也可以统一处理(CPU中只有加法器)
  • 补码和原码相互转化,其运算过程是相同的,不需要额外的硬件电路
  • 注意在内存窗口查看的时候会发现不是二进制而是十六进制,这个只是方便我们查看而已

(2)大小端的概念

①在内存中查看存储的数值

在这里插入图片描述
会发现00 00 00 64是被倒着放置的(小段模式)

②大端模式和小端模式

  • 大端字节序存储模式:数据低位字节存在内存的高地址,数据高位字节存在内存的低地址
  • 小端字节序存储模式:数据低位字节存在内存的低地址,数据高位字节存在内存的高地址

③出现大小端的原因

对于位数大于8位的处理器(如16位或者32位的处理器),由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题,因此就导致了大端存储模式和小端存储模式的出现。

(3)检验当前机器的大小端

//利用指针类型的转化可以检验大小端模式
int check_sys(void)
{
    int i = 1;
    return (*((char*)&i));
}
int main()
{
    int ret = check_sys();
    if (ret == 1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}
//另外一种写法,以后学习也可
int check_sys()
{
    union
    {
        int i;
        char c;
    }un;
    un.i = 1;
    return un.c;
}

(4)一些练习代码

①第一题

//输出什么?
#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;
}

这里就涉及到char的取值范围:
1、有符号char的取值范围[0 ~ 127]或者[ -128 ~ -1]即[-128 ~ 127],这里要注意-128的情况要理解成9位,不要把最高位理解成符号位,因为char只有8位被挤掉了……
2、无符号char的取值范围[0 ~ 255]

②第二题

#include <stdio.h>
int main()
{
    char a = -128;
    printf("%u\n", a);
    return 0;
} 
  • 原码:1000 0000 0000 0000 0000 0000 1000 0000
  • 反码:1111 1111 1111 1111 1111 1111 0111 1111
  • 补码:1111 1111 1111 1111 1111 1111 1000 0000
  • 截断:1000 0000
  • 提升:1111 1111 1111 1111 1111 1111 1000 0000
  • 打印4294967168
#include <stdio.h>
int main()
{
    char a = 128;
    printf("%u\n", a);
    return 0;
}
  • 原码:0000 0000 0000 0000 0000 0000 1000 0000
  • 反码:0111 1111 1111 1111 1111 1111 0111 1111
  • 补码:0111 1111 1111 1111 1111 1111 1000 0000
  • 截断:1000 0000
  • 提升:1111 1111 1111 1111 1111 1111 1000 0000
  • 还是打印4294967168

③第三题

int i= -20;
unsigned int j = 10;
printf("%d\n", i + j);//这里即使是i是int类型的会被提升为无符号int,但是还是存得下,只不过无符号的int会把符号位当成有效位,%d输出的时候依旧是会把这个位当成符号位来看
//按照补码的形式进行运算,最后格式化成为有符号整数
  • 原码:1000 0000 0000 0000 0000 0000 0001 0100(-20)
  • 反码:1111 1111 1111 1111 1111 1111 1110 1011
  • 补码:1111 1111 1111 1111 1111 1111 1110 1100
  • 截断:1111 1111 1111 1111 1111 1111 1110 1100(int)
  • 原、补、反码:0000 0000 0000 0000 0000 0000 0000 1010(10)
  • 相加后就是:1111 1111 1111 1111 1111 1111 1111 0110
  • 转化为补码:1111 1111 1111 1111 1111 1111 1111 0101
  • 转化为原码:0000 0000 0000 0000 0000 0000 0000 1010
  • 故打印出-10

④第四题

unsigned int i;
for(i = 9; i >= 0; i--)//由于无符号是没有负数的,就会导致unsigned int的类型是不存在负数的
{
    printf("%u\n",i);
}

⑤第五题

int main()
{
    char a[1000];
    int i;
    for(i=0; i<1000; i++)
    {
        a[i] = -1-i;
    }
    printf("%d", strlen(a));
    return 0;
}//会出现停止的情况,不会出现a[i]=-1000的情况,在a数组中只有值-1、-2、-3…-128、127、126…0、-1…而strlen会找到\0(即0)停止下来

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

(1)浮点型表示的范围和精度被定义在<float.h>中

(2)演示浮点数的存储例子

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;
}
//结果如下
//n的值为:9
//*pFloat的值为:0.000000
//num的值为:1091567616
//*pFloat的值为:9.000000
//这一行代码揭示了浮点类型和整形的存储是完全不同的

(3)浮点数的存储

①先得到SME的真实值

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

  • V= (-1)S * M * 2E
    • (-1)S表示符号位,S=0,V为正数;S=1,V为负数。
    • M表示有效数字,1<=M<2
    • 2E表示指数位

对于例子5.5来说,写成二进制为101.1,相当于1.011*22,相当于(-1)0*1.011*22,即:S=0,M=1.011,E=2

②再得到SME的计算值

在这里插入图片描述
在这里插入图片描述

①对于存储32位浮点数的话就会1bit存储S,8bit存储E,23bit存储M(即1+8+23=32)
②对于存储64位浮点数的话就会1bit存储S,11bit存储E,52bit存储M(1+11+52=64)
因此双精度浮点数比单精度浮点数要来的准确。

  • S:只用一个bit位存储,比较简单,直接进行存储
  • M:由于1<=M<2,因此M总是写成1.xxxxxxx的形式(二进制没有2,只有1和0),所以这个1可以被忽略舍去,只保存后面的小数位即可,等到读取的时候,再把这个1加上去。这样做的目的:一是节省1位有效数字,可以保存24位(原本23位),多了一位就提高了精度。另外,如果M填不完就会在后面补0(同理64位也是这么操作的)
  • E:而E的存储情况会比较复杂
    • 首先E是一个无符号十进制整数,它的bit位为8时,取值0 ~ 255;它的bit为11位时,取值为0 ~ 2047,然而实际上科学计数法是有负指数的情况出现的(存在E<0的情况),因此需要设置一个中间数
    • 用8bit存储E时,中间数为127(32位);用11bit存储E时,中间数位1023(64位)。比如210的E是10,存储进浮点数后就会变成E=10+127=137再存放到计算机里(如果值太小,加上127还是为负数,这就已经不是float能表示得了)
    • 再将十进制的计算值的E转化为二进制
  • 将S、M、E的值按照SEM的顺序连接存储起来即可

(4)浮点数的取出

浮点数被存储进了内存,现在计算机要把这个浮点数重新取出来,而取出来的话,主要的难点还是体现在E的问题上

  • 当计算值E不全为0或不全为1
    • 把E的计算值减去127(或者1023)得到原来的真实值
    • 再将有效数字M前加上被忽略的1
  • 当计算值E全为0
    • 说明原本的E真实值是-127(或者-1023),这个数实在是太小了。因此直接定义这时E的真实值就是1-127(或者1-1023)
    • 有效数字M也不再还回1,而是直接还原为0.xxxxxxx这样的小数
    • 以上做法是为了表示+/-0,以及接近于0的很小的数字
  • 当计算值E全为1
    • 说明原本的E真实值是128(或者1024),这个数就是+/-无穷大了

(5)利用规则解释前面的例子

  • 下面,让我们回到一开始的问题:为什么9还原成浮点数,就成了 0.000000 呢?
    • ①首先,将9转化为二进制进行拆分,在32位0 00000000 000000000000000 00001001得到第一位符号位s=0,后面8位的指数 E=00000000,
      最后23位的有效数字M=000 0000 0000 0000 0000 1001
    • ②由于指数E全为0,所以符合上一节的第二种情况。因此,浮点数V就写成:V=(-1)0×0.00000000000000000001001×2(-126)=1.001×2(-146)
    • ③显然,V是一个很小的接近于0的正数,所以用十进制小数表示就是0.000000
  • 再看例题的第二部分。请问浮点数9.0,如何用二进制表示?还原成十进制又是多少?
    • ①首先,浮点数9.0等于二进制的1001.0,即1.001×23。9.0 -> 1001.0 ->(-1)0×1.00123 -> s=0, M=1.001,E=3+127=130
    • ②那么,第一位的符号位s=0,有效数字M等于001后面再加20个0,凑满23位,指数E等于3+127=130,即10000010
    • ③所以,写成二进制形式,应该是S+E+M,即:0 10000010 00100000000000000000000
    • ④这个32位的二进制数,还原成十进制,正是 1091567616

噢对了,要注意补码的问题。我就老是忘记呢……上面的9是正数,原码就是其补码,故讨论起来少了转化成补码的一步。如果是负数,就一定要先转化成补码再讨论

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

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

相关文章

SAP ABAP——SAP简介(六)【ABAP技术栈简介】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计专业大二本科在读&#xff0c;阿里云社区专家博主&#xff0c;华为云社区云享专家&#xff0c;CSDN SAP应用技术领域新兴创作者。   在学习工…

黑吃黑的 Prynt Stealer 在恶意软件中嵌入后门

窃密对于网络犯罪来说&#xff0c;始终都是不可缺少的一部分。攻击者可以通过窃密获取更多信息&#xff0c;来判断攻击目标的价值高低&#xff0c;从而最大化自己的利益。为了使技术不太高的普通攻击者也能够使用&#xff0c;包括 Prynt Stealer 在内的信息窃取类恶意软件通常都…

工赋开发者社区 | 工业数字孪生:西门子工业网络与设备虚拟调试案例(TIA+MCD+SINETPLAN)

PART1案例背景及基本情况新生产系统的设计和实施通常是耗时且高成本的过程&#xff0c;完成设计、采购、安装后&#xff0c;在移交生产运行之前还需要一个阶段&#xff0c;即调试阶段。如果在开发过程中的任何地方出现了错误而没有被发现&#xff0c;那么每个开发阶段的错误成本…

Linux服务:Nginx服务重写功能

目录 一、重写功能 1、重写功能作用 2、rewrite指令 ①if指令 ②return指令 ③ set指令 ④break指令 3、rewrite标志 ①redirect标志 ②permanent标志 ③break标志 ④last标志 ⑤rewrite标志实验 一、重写功能 1、重写功能作用 重写功能(rewrite)用于实现URL的重…

CentOS 8利用Apache安装部署下载服务器

1&#xff1a;部署的目的是做一个类似下面开源镜像网站&#xff0c;把一些软件或者资料上传到服务器上面&#xff0c;减少用户在互联网上下载资料&#xff0c;提高效率&#xff0c;减少病毒。 2&#xff1a;使用下面的命令配置本机的IP地址主机名等信息。后期使用IP地址进行访问…

CRF条件随机场 | 关键原理+面试知识点

&#x1f604; CRF之前跟人生导师&#xff1a;李航学习过&#xff0c;这里结合自己的理解&#xff0c;精简一波CRF&#xff0c;总结一下面试中高频出现的要点。个人觉得没网上说的那么复杂&#xff0c;我看网上很大部分都是一长篇先举个例子&#xff0c;然后再说原理。没必要原…

webservice接口开发详解(.Net)

环境&#xff1a;win10 工具:Visual Studio2015 语言&#xff1a;vb.net WebService: 1.打开vs2015&#xff0c;新建visual basic项目&#xff0c;选择ASP.NET Web应用程序&#xff0c;单击确定 2.右键解决方案&#xff0c;添加新建项-Web-Web 服务(ASMX) 3.生成的WebServi…

Qt QMAKE_MSC_VER

文章目录摘要修改conf文件参考链接关键字&#xff1a; Qt、 QMAKE_MSC_VER 、 conf、 version、 关键字5摘要 今天在又有了新的小项目需要CV一下&#xff0c;但是第三方提供的是COM组件的库&#xff0c;所以第一步还是老实使用VS版本的Qt 来开发&#xff0c;以防不测&#xf…

3个月,入门网络安全并找到工作

在我进入大学之前&#xff0c;我一直对计算机感兴趣。虽然只是考了一个一般大学&#xff0c;但是选专业的时候还是选了计算机专业。 本来以为自己会在大学里学到很多有用的知识&#xff0c;并且能够很快找到一份好工作。但是&#xff0c;事实并不是这样。在大学期间&#xff0c…

深入浅出C++ ——哈希

文章目录前言一、unordered系列关联式容器1. unordered_map2. unordered_set二、哈希1. 哈希概念2. 哈希冲突3. 哈希函数4. 哈希冲突解决方法三、模拟实现unordered系列容器1. 哈希表的改造2. 模拟实现 unordered_set3. 模拟实现 unordered_map前言 在C11中&#xff0c;STL又提…

git之创建远程仓库

创建远程仓库 以下操作为演示在Github网站上创建远程仓库 1.登陆注册Github 2.创建仓库入口 3.编辑仓库信息 4.仓库创建完成 5.查看仓库地址 配置SSH 选择SSH操作 如果某台电脑需要与Github上的仓库交互&#xff0c;那么就要把这台电脑的SSH公钥添加到…

TestNG和Junit的区别,测试框架该如何选择?

要想知道两个框架的区别&#xff0c;首先分别介绍一下两个框架。 TestNG是一个java中的开源自动化测试框架&#xff0c;其灵感来自JUnit和NUnit&#xff0c;TestNG还涵盖了JUnit4整个核心的功能&#xff0c;但引入了一些新的功能&#xff0c;使其功能更强大&#xff0c;使用更…

【更新公告】Airtest更新至1.2.9版本

1. 前言 本次更新为Airtest库更新&#xff0c;版本提升至1.2.9&#xff0c;主要新增 对Android13的支持 、新增Windows和iOS的录屏接口 等。 2. 更新功能 1&#xff09;新增对Android13的支持 Airtest1.2.9版本新增了对Android13设备的支持&#xff0c;有该系统设备连接/自…

第二章 编写MBR主引导记录

主引导记录&#xff08;MBR&#xff0c;Master Boot Record&#xff09;是采用MBR分区表的硬盘的第一个扇区&#xff0c;即C/H/S地址的0柱面0磁头1扇区&#xff0c;也叫做MBR扇区 计算机的启动过程 为什么程序要载入内存 CPU的硬件电路被设计成只能运行处于内存中的程序&…

前端开发常用的18个JavaScript框架和库

JavaScript 可以说是最流行的编程语言之一&#xff0c;也是Web 开发人员必须学习的 3 种语言之一&#xff0c;JavaScript 几乎可以做任何事情&#xff0c;更可以在包括物联网在内的多个平台和设备上运行。在WebGL库和SVG/Canvas元素的支持下&#xff0c;JavaScript变得惊人的强…

Spring Cloud Nacos源码讲解(四)- Nacos服务端服务注册源码分析

Nacos服务端服务注册源码分析 服务端调用接口 ​ 我们已经知道客户端在注册服务的时候实际上是调用的NamingService.registerInstance这个方法来完成实例的注册&#xff0c;而且在最后我们也告诉了大家实际上从本质上讲服务注册就是调用的对应接口nacos/v1/ns/instance&#…

网络工程(三)ensp配置静态路由

配置静态路由 这里选择的路由器是AR2220 因为有三个GE接口 下面说拓扑图 一、定义AR路由ip地址和下一条 AR1system-viewsysname AR1interface g0/0/0ip address 10.0.0.254 8interface g0/0/1ip address 50.0.0.1 8下一条代码[AR1]ip route-static 0.0.0.0 0 50.0.0.2AR2 s…

Linux SID 开发指南

Linux SID 开发指南 1 前言 1.1 编写目的 介绍Linux 内核中基于Sunxi 硬件平台的SID 模块驱动的详细设计&#xff0c;为软件编码和维护提供基 础。 1.2 适用范围 内核版本Linux-5.4, Linux-4.9 的平台。 1.3 相关人员 SID 驱动、Efuse 驱动、Sysinfo 驱动的维护、应用开…

Java 方法超详细整理,适合新手入门

目录 一、什么是方法呢&#xff1f; 二、方法的优点 三、带返回值方法定义 语法&#xff1a; 示例&#xff1a; 四、带返回值方法调用 语法&#xff1a; 示例&#xff1a; 五、结果示例 一、什么是方法呢&#xff1f; Java方法是语句的集合&#xff0c;它们在一起执行…

Android 9.0 仿ios的hotseat效果修改hotseat样式

1.概述 在9.0的系统rom定制化的产品中,在launcher3的定制化需求中,有很多功能需求点需要开发,在对一下ui的定制化的过程中,会参考ios的样式进行定制化,所以最近项目需求 要求仿ios的hotseat的样式来进行产品的定制,开发一款仿ios的hotseat,所以需要对hotseat进行分析,然…