c语言

您所在的位置:网站首页 c语言内存地址查找 c语言

c语言

2023-09-15 10:19| 来源: 网络整理| 查看: 265

文章目录 数据类型的详细介绍整形在内存中存储:原码,反码,补码大小端字节序介绍及判断浮点型在内存中的存储解析

数据类型的详细介绍

现在我们来简单介绍一下在c语言中的常见的数据类型以及它们的范围:

char //字符数据类型 short //短整型 int //整形 long //长整型 long long //更长的整形 float //单精度浮点数 double //双精度浮点数

在这里插入图片描述 在这里插入图片描述 类型的意义:

使用这个类型开辟内存空间的大小(大小决定了使用范围)。如何看待内存空间的视角

计算每种类型在内存中开辟的空间: c语言中有那么多的数据类型,那么这些数据类型在内存中开辟的空间又是多少呢?其实在c语言中早就为我们准备了专门计算数据类型的操作符(sizeof) 在这里插入图片描述 类型的分类总结: 整形兄弟们 在这里插入图片描述 浮点型兄弟们 float double

还有别的类型在这里我们就不加以讨论了,本篇文章仅仅讨论整形与浮点型在内存中的存储

整形在内存中存储:原码,反码,补码

我们之前讲过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。在以下代码中我们知道a占4个字节也就是八个比特位,大家有没有想过a = 5,是以什么形式存储的?接下来我们谈谈数据在所开辟内存中到底是如何存储的?

#include int main() { int a = 5; return 0; }

接下来我们来了解以下概念: 计算机中的整数有三种表示方法,即原码、反码和补码。 正整数:原反补三码相同 负整数: 原码:直接将二进制按照正负数的形式翻译成二进制就可以。 反码:将原码的符号位不变,其他位依次按位取反就可以得到了。 补码:反码加一得到补码。 对于整形来说:数据在内存中的存储其实是补码

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

经过以上总结想必大家应该清楚整形在内存中的存储是以补码的方式进行,接下来我们来举一个简单的例子(int a = 20;int b = -10)

在上面我们讲到的整形在内存中的存储是以二进制的补码进行的,我们将20转换成二进制(00000000000000000000000000010100)然后转换成反码(01111111111111111111111111101011) 再转换成补码得到(01111111111111111111111111101100),在vc2019中打开调试选择查看内存,我们会发现在vc2019中显示存储的方式是以十六进制的方式显示的,不过并不影响我们研究(a的十六进制是00000014,b的十六进制是ff ff ff f6)但是顺序好像有点不相同?为什么它是倒着存储的呢? 在这里插入图片描述

大小端字节序介绍及判断

上面我们讲到为什么20的十六进制是倒着存储的问题,接下来我将要给大家介绍一个新的概念

大小端介绍 什么是大端小端: 大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地 址中; 小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地 址中。 为什么有大端和小端: 为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单 元都对应着一个字节,一个字节为8 bit。但是在C语言中除了8 bit的char之外,还有16 bit的 short型,32 bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位 或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。 例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为 高字节, 0x22 为低字节。对于大端模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高 地址中,即 0x0011 中。小端模式,刚好相反。我们常用的 X86 结构是小端模式,而 KEIL C51 则 为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式 还是小端模式。 那么我们如何清楚的知道我们所使用的计算机是大端存储还是小端存储呢?给大家分享以下代码,大家可以用自己的电脑试试看:

#include int check_sys() { int i = 1; return (*(char*)&i); } int main() { int ret = check_sys(); if (ret == 1) { printf("小端\n"); } else { printf("大端\n"); } return 0; }

在这里插入图片描述

浮点型在内存中的存储解析

讲完整形在内存中的存储我们接下来就该进入浮点型的探讨了 我们先来举一个例子:

#include 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; }

大家可以先自己想想这个题打印出来的结果是什么?在这里插入图片描述 接下来给大家贴答案: 在这里插入图片描述 num 和 *pFloat 在内存中明明是同一个数,为什么浮点数和整数的解读结果会差别这么大?要理解这个结果,一定要搞懂浮点数在计算机内部的表示方法,小伙伴们如果做出来能不能在评论区分享一下你们的做题思路,如果暂时没有想到的话那么接下来我给大家来讲解一下我的做题思路:

其实在c语言中关于浮点型的存储早就做过如下规定: 详细解读: 根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式: (-1)^S * M * 2^E (-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。 M表示有效数字,大于等于1,小于2。 2^E表示指数位。 举例来说: 十进制的5.0,写成二进制是 101.0 ,相当于 1.01×2^2 。 那么,按照上面V的格式,可以得出s=0,M=1.01,E=2。 十进制的-5.0,写成二进制是 -101.0 ,相当于 -1.01×2^2 。那么,s=1,M=1.01,E=2。 IEEE 754规定: 对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。 在这里插入图片描述 对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。 在这里插入图片描述 当然还有一些特殊情况比如:E全为0 这时,浮点数的指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于 0的很小的数字。

下面,让我们回到一开始的问题:为什么 0x00000009 还原成浮点数,就成了 0.000000 ? 首先,将 0x00000009 拆分,得到第一位符号位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×2^3 那么,第一位的符号位s=0,有效数字M等于001后面再加20个0,凑满23位,指数E等于3+127=130, 即10000010。 所以,写成二进制形式,应该是s+E+M,即0 10000010 001 0000 0000 0000 0000 0000 这个32位的二进制数,还原成十进制,正是 1091567616



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3