数据在内存中的存储(一个新手的理解)

news2024/11/23 20:15:11

1.整数在内存中的存储

  正整数的原,补,反码都相同。

  负整数的三种表示方法各不相同。

提示:负数的反码等于原码符号位不变,其他位置的二进制位取反。

           负数的补码等于反码+1.

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

  为什么呢?

  使⽤补码,可以将符号位和数值域统⼀ 处理;

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

首先看一个代码(VS系统)

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

 这个代码的结果呢?

可以看出低位的数字存储在了前面;这是小端存储

2.1什么是大小端?

超过一个字节的数据在内存中存储时,就有存储顺序的问题,按照不同的存储顺序,我们可以把分为大端字节存储和小端字节存储。在不同的编译器中不同。

大端存储:通俗来说就是数字的比较大的位数存到了前面。就像 0x11223344,如果为大端存储的话那在内存里面 先存储的就是 11 22 33 44,和上面的图片相反

小端存储:就是数字的比较小的位数存到了前面。和上图一样!!!

一个自编小口诀,前大大,前小小。就是前面如果是数字位数大的数字的话就是大端存储,反之相同。

2.2为什么有大小端呢?

每个地址单元都 对应着⼀个字节,⼀个字节为8 bit 位,但是在C语⾔中除了8 bit 的 char 之外,还有16 bit 的 short 型,32 bit 的 long 型(要看具体的编译器),另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度⼤于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储模式和⼩端存储模式。

2.3那怎么知道编译器是什么存储呢?

可以写一个小代码来研究

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

 这个代码这样看,在最上面的check 函数中先给 int i = 1,之后返回时将 i 的 强制转换为 char * 是因为 本来 存储的是 int 变量 占了4个字节 ,如果把这个 存储的 字节 单独拿出来看呢, 如果 前面 第一个 字节存的 是 01,那就代表了 将小位的数字存在了前面,为小端存储,反之相同。

2.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;
}

输出结果a b = -1,c =255.

这个练习,可以看出用char 来存储数字,但存储数字的时候存的是补码。因为char 其实是signed char的缩写。所以a b 其实是相同的。因为 sighed char 是有符合的字符型,只保存一个字节,所以 3个变量的二进制位都是 11111111.因为前两个变量是有符号的,所以在下面要求打印%d 时发生整型提升,因为两个变量是有符号的,所以提升时前面的符号位为1.所以提升时32个二进制位全为1 。但打印时 是以原码打印,因为前两个变量的符号位是1 是负数。负数的原码 等于 补码减一 并取反。所以最终前两个变量的 原码就是 第一位二进制位和最后一位二进制位为1,其他全为0,所以等于-1.

但不同的是 unsighed char 因为 是无符号整型,在整形提升时,c变量的二进制位前面全部补0.所以c 的二进制表示是 00000000 00000000 00000000 11111111.因为正数的原反补码相同所以,c = 255.

#include <stdio.h>
int main()
{
 char a = -128;
 printf("%u\n",a);
 return 0;
}





#include <stdio.h>
int main()
{
 char a = 128;
 printf("%u\n",a);
 return 0;
}

第一个a 打印出来一个特别大的数字,第二个char

这个练习要求打印 %u 就是无符号整型。给的两个有符号的 char 类型。

第一个 char 因为是负的-128,所以他的 原码其实就是 10000000,对他整型提升后 就是。

11111111 11111111 11111111 10000000,因为要打印无符号整型,所以第一个二进制位不看做符号位。,所以这个数字是正数,原码反码补码相同,所以打印出来一个特别大的数字。

第二个 a 其实写下来和第一个a 的原码其实是一样的,因为 char 只有 一个字节8个二进制位。-128 和 128的二进制位其实相同,所以两个数字的结果相同。

#include <stdio.h>
int main()
{
 char a[1000];
 int i;
 for(i=0; i<1000; i++)
 {
  a[i] = -1-i;
 }
  printf("%d",strlen(a));
  return 0;
}

 

 这个代码的最终结果是255.

为什么呢?首先给了一个 1000的i 循环。将a【i】 = -1 - i;

因为a 【i】是char 类型 只有 1个字节 8 个二进制位。第一个a【i】 = -1.二进制位是

10000001.每次都减一直到 11111111 ,它的原码就是 10000000.在vs 中这个数字为-128

所以-128再减一 就变成了 127 在一直减到 00000000.其中总共走了 255次。出现 0 。

strlen 计算字符直到出现 0.所以得出255.

 

#include <stdio.h>
unsigned char i = 0;
int main()
{
 for(i = 0;i<=255;i++)
 {
 printf("hello world\n");
 }
 return 0;
}

 

无符号char型的范围如上图。

本题的无符号char 类型 的范围 0 -255.因为for 循环一直打印到255.但255加一 又 等于 0.

这就会导致死循环。

 

#include <stdio.h>
int main()
{
	unsigned int i;
	for (i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
	}
	return 0;
}

这题也是一个死循环,因为是无符号整型,所以当减到0时,再减一,就变成了 32个二进制位都是 1.这样一直循环下去。 

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

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

3.1练习

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

由上图可以看出浮点数和整型的存储方式是不同的

3.2浮点数的储存 

上图则是浮点数在计算机内部的表示方法。

⼗进制的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。
对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

3.2.1 浮点数存的过程

M保证是 1<=M<2.

E如果为8位取值范围就是0-255,如果为11位就是0-2047.根据IEEE的规定,需要给E中额外存入一个数字 8位E就是 127 ,11位就是 1023.⽐如,2^10的E是 10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。

3.2.2浮点数取的过程

指数E从内存中取出还要分为三种情况。

1.E不全为0或1.
这时,浮点数就采⽤下⾯的规则表⽰,即指数E的计算值减去127(或1023),得到真实值,再将有效
数字M前加上第⼀位的1。
⽐如:0.5 的⼆进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0*2^(-1),其
阶码为-1+127(中间值)=126,表⽰为01111110,⽽尾数1.0去掉整数部分为0,补⻬0到23位
E全为0
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,⽽是还
原为0.xxxxxx的⼩数。这样做是为了表⽰±0,以及接近于0的很⼩的数字。
E全为1
这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s);
好了,关于浮点数的表⽰规则,就说到这⾥。

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

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

相关文章

【软件测试】自动化测试selenium(一)

文章目录 一. 什么是自动化测试二. Selenium的介绍1. Selenium是什么2. Selenium的特点3. Selenium的工作原理4. SeleniumJava的环境搭建 一. 什么是自动化测试 自动化测试是指使用软件工具或脚本来执行测试任务的过程&#xff0c;以替代人工进行重复性、繁琐或耗时的测试活动…

C++(List)

本节目标&#xff1a; 1.list介绍及使用 2.list深度剖析及模拟实现 3.list和vector对比 1.list介绍及使用 1.1list介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list的底层是双向链表结构&#xff0c;…

[React] react-redux基本使用

文章目录 1.redux2.安装redux3.操作redux3.1 创建最为核心的store3.2 创建为store工作的reducer3.3 redux的响应式处理 4.完整版redux4.1 完善actionCreators4.2 thunk中间件 5.react-redux5.1 Count容器组件5.2 connect函数5.3 Provider 1.redux redux原理图 actionCreators:…

司空见惯 - 奈尔宝的NTTP

联合国对21世纪人才定义的标准&#xff0c;包括六种核心技能&#xff0c;即批判性思维&#xff08;critical thinking)、人际交往&#xff08;communication)、与人合作&#xff08;collaboration)、创造性&#xff08;creativity)、信息素养&#xff08;information literacy)…

【中国知名企业高管团队】系列25:360

今天华研荟的“走进中国知名企业高管团队系列”带大家走进360——这是少数以数字作为产品名称的公司&#xff0c;如果您在网上看到有人说“数字公司”&#xff0c;那么大概率指的就是360公司。 360公司正式的名称是三六零安全科技股份有限公司&#xff0c;可以说是中国覆盖面最…

数据结构: 数组与链表

目录 1 数组 1.1 数组常用操作 1. 初始化数组 2. 访问元素 3. 插入元素 4. 删除元素 5. 遍历数组 6. 查找元素 7. 扩容数组 1.2 数组优点与局限性 1.3 数组典型应用 2 链表 2.1 链表常用操作 1. 初始化链表 2. 插入节点 3. 删除…

正确完成实时 AI

发表于 构建真实世界的实时 AI 一、说明 我们知道&#xff0c;当前的AI进展是扎根于历史数据&#xff0c;这就造成一个事实&#xff0c;模型总是赶不上实时进展&#xff0c;模型的洞察力不够尖锐&#xff0c;或者&#xff0c;时间损失等&#xff0c;本篇对这一系列AI的短板展开…

【初识Linux】:常见指令(1)

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关Linux的基础知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数…

WebSocket基础——WebSocket的基本概念 VS Http SpringBoot整合WebSocket vue前端代码和效果展示

前言 WebSocket是一种在Web浏览器和服务器之间进行全双工通信的协议。它允许在单个TCP连接上进行双向通信&#xff0c;而不需要通过多个HTTP请求-响应循环来实现。相比传统的HTTP请求&#xff0c;WebSocket提供了更低的延迟和更高的实时性。 本篇博客介绍WebSocket的基本概念…

计算机网络(四):网络层

参考引用 计算机网络微课堂-湖科大教书匠计算机网络&#xff08;第7版&#xff09;-谢希仁 1. 网络层概述 网络层的主要任务是实现网络互连&#xff0c;进而实现数据包在各网络之间的传输 要实现网络层任务&#xff0c;需要解决以下主要问题 网络层向运输层提供怎样的服务 (“…

基于SpringBoot的养老监护管理平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

解决Invalid bound statement (not found)错误~

报错如下所示&#xff1a; 找了好久&#xff0c;刚开始以为是名称哪里写的有问题&#xff0c;但仔细检查了好多遍都不是 最后发现了问题如下所示&#xff1a; UserMapper里面的内容被我修改了&#xff0c;但classes中的内容还是原来的内容&#xff0c;所以才导致了编译器报错n…

Vue2详解

Vue2 一、Vue快速上手 1.1什么是Vue 概念&#xff1a;Vue是一套构建用户界面的渐进式 框架 构建用户界面&#xff1a;基于数据渲染出用户可以看到的界面 渐进式&#xff1a;所谓渐进式就是循序渐进&#xff0c;不一定非得把Vue中所有的API都学完才能开发Vue&#xff0c;可以…

【数据结构】红黑树(C++实现)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【数据…

一篇博客学会系列(3) —— 对动态内存管理的深度讲解以及经典笔试题的深度解析

目录 动态内存管理 1、为什么存在动态内存管理 2、动态内存函数的介绍 2.1、malloc和free 2.2、calloc 2.3、realloc 3、常见的动态内存错误 3.1、对NULL指针的解引用操作 3.2、对动态开辟空间的越界访问 3.3、对非动态开辟内存使用free释放 3.4、使用free释放一块动态…

接口测试入门实践

简单接口搭建(表单/REST) 五步教会你写接口 首先要安装flask包: pip install flask 从flask中导入Flask类和request对象: from flask import Flask, request从当前模块实例化出一个Flask实例:appFlask(__name__)编写一个函数来处理请求 从请求对象中获取数据:arequest.values.…

【test】文章测试

自定义文章测试 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个注脚注…

【改进哈里鹰算法(NCHHO)】使用混沌和非线性控制参数来提高哈里鹰算法的优化性能,解决车联网相关的路由问题(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

嵌入式学习笔记(42)SD卡的编程接口

8.3.1 SD卡的物理接口 SD卡由9个针脚与外界进行物理连接&#xff0c;这9个脚中有2个地&#xff0c;1个电源&#xff0c;6个信号线。 8.3.2 SD协议与SPI协议 (1)SD卡与SRAM/DDR/SROM之类的东西的不同&#xff1a;SRAM/DDR/SROM之类的存储芯片是总线式的&#xff0c;只要连接上…

Docker部署Nginx-常用命令

1.拉取 docker pull nginx 2. 查看镜像 docker images 3.保存镜像 docker save -o nginx.tar nginx:latest 4.删除镜像 docker rmi nginx:latest 5. 加载镜像 docker load -i nginx.tar 6. 运行Nginx docker run -d --name nginx -p 80:80 nginx 7.停掉Nginx容器 docker stop n…