揭示数据在内存中存储的秘密!

** **
悟已往之不谏,知来者犹可追 **
** 创作不易,宝子们!如果这篇文章对你们有帮助的话,别忘了给个免费的赞哟~


整数在内存中的存储

整数的表达方式有三种:原码、反码、补码。
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位最高位的⼀位是被当做符号位,剩余的都是数值位。
正整数的原、反、补码都相同。 负整数的三种表示方法各不相同。

  • **原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。 **
  • **反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。 **
  • 补码:反码+1就得到补码**。**

对于整形来说:数据存放内存中其实存放的是补码。
为什么呢?

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

大小端字节序和字节序判断

当我们了解了整数在内存中存储后,我们调试看⼀个细节:

#include <stdio.h>
int main()
{int a = 0x11223344;return 0;
}

image.png
我们可以注意到十六进制的a0x11223344在VS中以44 33 22 11的形式存储~
这是为什么呢?


什么是大小端

**其实超过⼀个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,我们分 为大端字节序存储和小端字节序存储,下面是具体的概念: **

  • **大端(存储)模式:是指数据的低位字节内容保存在内存的高地址处,而数据的高位字节内容,保存 在内存的低地址处。 **
  • 小端(存储)模式:是指数据的低位字节内容保存在内存的低地址处,而数据的高位字节内容,保存 在内存的高地址处。

** 上述概念需要记住,方便分辨大小端。 **

image.png


为什么有大小端

**为什么会有大小端模式之分呢? 这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8 bit位,但是在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处理器还可以由硬件来选择是 大端模式还是小端模式。 **


整形提升与算数转换

整形提升

  1. C语言中整型算术运算总是至少以缺省整型类型的精度来进行的。
  2. 为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
  3. **整形提升的意义:表达式的整型运算要在CPU的相应运算器件内执⾏,CPU内整型运算器(ALU)的操作数的字节⻓度⼀般就是int的字节⻓度,同时也是CPU的通⽤寄存器的⻓度。
    因此,即使两个char类型的相加,在CPU执⾏时实际上也要先转换为CPU内整型操作数的标准⻓度。
    通⽤CPU(general-purposeCPU)是难以直接实现两个8⽐特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种⻓度可能⼩于int⻓度的整型值,都必须先转换为int或unsigned int,然后才能送⼊CPU去执⾏运算
    **
 //实例1
char a,b,c;
...
a = b + c;

**b和c的值被提升为普通整型,然后再执行加法运算。
加法运算完成之后,结果将被截断,然后再存储于a中。 **

** 如何进行整体提升呢?**

  1. 有符号整数提升是按照变量的数据类型的符号位来提升的
  2. 无符号整数提升,高位补0
//负数的整形提升
char c1 = -1;
变量c1的⼆进制位(补码)中只有8个⽐特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,⾼位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的⼆进制位(补码)中只有8个⽐特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,⾼位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//⽆符号整形提升,⾼位补0

算数转换

**如果某个操作符的各个操作数属于不同的类型,那么除非其中⼀个操作数的转换为另⼀个操作数的类
型,否则操作就无法进行。下⾯的层次体系称为寻常算术转换。 **

long double
double
float
unsigned long int
long int
unsigned int
int
  • **如果某个操作数的类型在上面这个列表中排名靠后,那么首先要转换为另外⼀个操作数的类型后执行
    运算。 **

一个小练习

  • **请简述大端字节序和小端字节序的概念,设计⼀个小程序来判断当前机器的字节序。(10分)-百度笔 试题 **
/代码1 
#include <stdio.h>
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;
}
//代码2 
int check_sys()
{union{int i;char c;}un;un.i = 1;return un.c;
}

浮点数在内存中的存储

浮点数的存储

常见的浮点数:3.14159、1E10等,浮点数家族包括: float、double、long double 类型。浮点数表示的范围: float.h 中定义

#include <stdio.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;
}
输出结果是什么呢?

image.png
上面的代码中, num 和 *pFloat 在内存中明明是同⼀个数,为什么浮点数和整数的解读结果会差别 这么⼤? 要理解这个结果,⼀定要搞懂浮点数在计算机内部的表示方法。
根据国际标准IEEE(电气和电子工程协会)754,任意⼀个⼆进制浮点数V可以表示成下面的形式:
image.png
IEEE754规定:

  • 对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
  • 对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
  • image.png

浮点数存的过程

IEEE 754对有效数字M和指数E,还有⼀些特别规定。
** 前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中 xxxxxx 表示小数部分**


IEEE 754规定,在计算机内部保存M时,默认这个数的第⼀位总是1,因此可以被舍去,只保存后面的 xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第⼀位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保 存24位有效数字。


至于指数E,情况就比较复杂
首先,E为⼀个无符号整数(unsigned int)
这意味着,如果E为8位,它的取值范围为0255;如果E为11位,它的取值范围为02047。但是,我 们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上 ⼀个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,2^10的E是 10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。

浮点数取的过程

image.png

前面题目的解析

image.png

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

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

相关文章

[java基础揉碎]多态参数

多态参数 方法定义的形参类型为父类类型&#xff0c;实参类型允许为子类类型 例子: 定义一个员工类, 有名字和工资两个属性, 有年工资的方法 定义一个普通员工继承了员工类 , 重写了年工资的方法 定义一个经理类, 也继承了员工类, 同时经理多以了一个奖金的属性, 重写的年…

Linux高级IO_select、epoll

调用send/write、read/recv这些IO接口进行网络通信时&#xff0c;需要等待IO条件满足&#xff08;IO事件就绪&#xff09;才能正常拷贝数据。比如调用send/write需要等待TCP的发送缓冲区有剩余空间才能将数据拷贝到TCP发送缓冲区中&#xff0c;调用read/recv需要等待TCP的接收缓…

Java双非大二找实习记录

先说结论&#xff1a;2.22→3.6线上线下面了七家&#xff0c;最后oc两家小公司&#xff0c;接了其中一个。 本人bg&#xff1a; 真名不经传双非一本&#xff0c;无绩点无竞赛无奖项无实习&#xff0c;23年12月开始学java。若非要说一点相关的经历&#xff0c;就是有java基础&…

Python+Selenium- 环境搭建

一&#xff0c;Selenium 简介 Selenium是目前最流行的web自动化测试工具&#xff0c;也常用于网络爬虫&#xff0c;已经更新到3以上的版本。 1&#xff0c;组件 它提供了以下web自动化测试组件&#xff1a; Selenium IDE&#xff0c;Firefox浏览器的一个插件&#xff0c;提供…

CSS学习(2)-盒子模型

1. CSS 长度单位 px &#xff1a;像素。em &#xff1a;相对元素 font-size 的倍数。rem &#xff1a;相对根字体大小&#xff0c;html标签就是根。% &#xff1a;相对父元素计算。 注意&#xff1a; CSS 中设置长度&#xff0c;必须加单位&#xff0c;否则样式无效&#xff…

JavaScript入门-引入方式-基础语法

JavaScript-引入方式 引入方式1 <script >... ...</script> 在.html文件内部任何位置引入都可以 引入方式2 <script src"... ..."></script> 在.html文件外部创建js文件夹在文件夹里面创建.js文件 基础语法 书写语法 // 弹出警告窗 wind…

印度交易所股票行情数据API接口

1. 历史日线 # Restful API https://tsanghi.com/api/fin/stock/XNSE/daily?token{token}&ticker{ticker}默认返回全部历史数据&#xff0c;也可以使用参数start_date和end_date选择特定时间段。 更新时间&#xff1a;收盘后3~4小时。 更新周期&#xff1a;每天。 请求方式…

VMware虚拟机硬盘容量扩容方法

扩容后不会影响原文件。亲测有效&#xff0c;高效便捷 - 在关机状态下&#xff0c;先在VM上直接扩容硬盘容量&#xff0c;输入扩容后的硬盘最大容量 注意&#xff0c;如果想在原硬盘上增加容量&#xff0c;需要将原来的快照都删除 - 输入最大磁盘大小 运行虚拟机进入系统&…

docker搭建vulfocus靶场

靶场搭建的前提是具备docker容器的环境 环境准备&#xff1a; 在kali上安装docker 先是进行软件和源更新 sudo apt-get update开始安装 sudo apt-get install -y docker.io设置开机自启动 sudo systemctl enable docker --now查看状态 sudo systemctl status docker给当…

B端界面又丑又乱,也不会总结规范,来,我给5个规范模板,照着学

发5个别人总结的规范&#xff0c;一定会对你的B端系统改进&#xff0c;有帮助的。

leedcode刷题--day8

28 最长回文子串 采用动态规划的方式 首先如果子串长度为1的话&#xff0c;一定是回文子串如果子串长度为2&#xff0c;那如果第一个字母第二个字母&#xff0c;即为回文子串如果bababd中babab为回文子串&#xff0c;那么除去左边界和右边界后的也是回文子串 class Solution(…

ping和telnet的区别

ping是ICMP协议&#xff0c;只包含控制信息没有端口&#xff0c;用于测试两个网络主机之间网络是否畅通 telnet是TCP协议&#xff0c;用于查看目标主机某个端口是否开发。 总结&#xff1a;ping是物理计算机间的网络互通检查&#xff0c;telnet是应用服务间的访问连通检查&am…