数据在内存的存储
整数在内存中的存储
我们来回顾一下,整数在计算机是以补码的形式进行存储的,整数分为正整数和负整数,正整数的原码、反码和补码是一样的,负整数的原码、反码和补码略有不同(反码是原码除符号位,其他位按位取反(即0变成1,1变成0),补码就是反码+1),负整数的补码变为原码也是一样的,保留符号位,其他位按位取反,再+1就可以得到原码。
在计算机储存数据的时候,会有一个符号位(最开头的数位用1来表示负数,用0来表示正数)来表示正负,剩下的是数值位来表示数值。正数的原码、反码和补码是完全一样的,这里注意符号位是不会变的,负数的反码就是除了原码的符号位不变之外,其他位按位取反(就是0变成1,1变成0),补码就是在反码的基础上加1
这里我们以32位机器来举例:

大小端字节序
我们来引入一个例子

大家是不是看到存储的数据是倒过来的,当数据超过一个字节的时候就会出现字节存储的顺序问题,这就是大小端字节序存储的问题。
解释
大端字节序就是数据的高位存到低地址处,低位存到高地址处。
小端字节序就是数据的低位存到低地址处,高位存到高地址处。
我们以从左到右是从低地址到高地址进行增加为例:

由此可见,开始我们引入的例子是按小端存储的,我是用VS2022来演示的。
练习
问题一
设计代码来判断当前机器的字节序
我们可以使用一个数字来进行判断,这里我使用数字1,数字1的十六进制表示为0x00000001,我们只要拿出第一个字节就可以判断大小端存储了,如果拿出的是0,就是大端字节序存储,如果拿出的是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;
}
代码分析题
代码一
#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有没有符号取决于编译器的,我这里使用的是VS2022,char是有符号的,所以a和b 就会打印-1,但是c 就不一样,首先-1在内存中的原码是10000001,反码是11111110,补码是11111111,由于 c 是无符号的,所以在内存中的11111111的第一个1就不会解读为符号位,而是正常的数位,所以打印255。
来看一下运行结果:

代码二
#include <stdio.h>int main()
{char a = -128;printf("%u\n", a);return 0;
}
首先 -128 写出二进制为1000 0000 0000 0000 0000 0000 1000 0000,反码为1111 1111 1111 1111 1111 1111 0111 1111,补码为1111 1111 1111 1111 1111 1111 1000 0000,由于是char 类型,所以发生截断,以八个比特位来进行保存,就是1000 0000,以%u的形式打印,%u是无符号的整型(就是unsigned int 类型),所以发生整型提升,就变成1111 1111 1111 1111 1111 1111 1000 0000,这个数字我们拿计算机算一下,就会得出

来看一下运行结果:

代码三
#include <stdio.h>int main()
{char a = 128;printf("%u\n", a);return 0;
}
128 的原码是 0000 0000 0000 0000 0000 0000 1000 0000,由于是整数,所以原码反码补码是一样的。由于是char 类型发生截断,保留八个比特位,就是1000 0000,用%u来进行打印,发生整型提升,由于char 是有符号的,所以提升为1111 1111 1111 1111 1111 1111 1000 0000 ,然后打印,由于是无符号的整数打印,其实结果和上一道题目的结果是一样的。

代码四
#include <stdio.h>
#include <string.h>int main()
{char a[1000];int i;for (i = 0; i < 1000; i++){a[i] = -1 - i;}printf("%d", strlen(a));return 0;
}
这个我们就要思考 char 是有取值范围的,-128~127,一共有256个数字,strlen遇到\0,就会停止计算,这里的a从-1开始存储,当a变为-128时,再减一就会变成127,一直减到0,之后减一变为-1,依次类推形成一个循环结构,就如下图所示,所以,strlen(a)的计算结果应该是0之前的255个数。

来验证一下:

代码五
#include <stdio.h>unsigned char i = 0;int main()
{for (i = 0; i <= 255; i++){printf("hello world\n");}return 0;
}
这个代码还是一样,拿出我们的循环图:

当 i 从 1 开始,加到255时,再加1 就不是256,而是255,所以不会跳出循环,而是一个死循环。
代码六
#include <stdio.h>int main()
{unsigned int i;for (i = 9; i >= 0; i--){printf("%u\n", i);}return 0;
}
这个代码其实不用画循环图也能做,因为unsigned int 是无符号的整数,i 永远大于等于0,所以这还是一个死循环。
代码七
#include <stdio.h>//x86环境,小端字节序存储int main()
{int a[4] = { 1, 2, 3, 4 };int* ptr1 = (int*)(&a + 1);int* ptr2 = (int*)((int)a + 1);printf("%x,%x", ptr1[-1], *ptr2);return 0;
}
先看ptr1:

&a取出的是整个数组的地址,&a+1是跳过整个数组,ptr1[-1] = (ptr+(-1)),由于prt1是int类型的,所以ptr1-1就会往后移动一个int,解引用就是指向 4
ptr2:
由于是小端字节序存储,我们来画一下内存图:

由于a 是数组首元素的地址,所以 a 其实指向 1 ,由于(int) a 强制类型将a转换为int类型,+1后就是a的地址+1,指向01后面的00,由于ptr2是int*类型,搜易解引用就会取出四个字节的数据,也就是0x02 00 00 00
浮点数在内存中的存储
首先我们要知道浮点数的存储和整数的存储是不一样的,不信的可以看一下下面的运行截图:

现在我们来探讨一下浮点数在内存中是如何存储的:
由于浮点数的存储比较复杂,为了方便大家快速了解,我对此进行了一下总结:
首先,一个公式:(-1)^S * M * 2^ E , 浮点数也是有符号的,所以我们用S(二进制位,所以S只能取 0 或 1)来控制(-1)的0或1次方进而也就控制了浮点数的正负性,然后就是我们将浮点数化成类似科学计数法的形式(在二进制里,我们化成1.xxxx*2^E), 之后我们去掉1留下的来的xxxxx就是M,而E的处理就有点复杂,因为E可能为负数,所以为了避免负数的情况我们将其加上一个中间数(127或者1023)
注意了:浮点数的二进制表示,如0.5,怎么表示小数部分,要注意小数点后面浮点数的二进制权重是从2^ (-1)、 2^ (-2)、2^ (-3)…依次叠加的,所以我们要凑出0.5,也就是1,因为1*2^(-1)就是0.5
我们来看一下32位的float和64位的double存储情形:

E加中间数也是根据浮点数的类型进行加的,32的float加127,64位的double 加1023
正常情况下:
E不为全0或全1,那就是正常处理,减去中间数,取出S得到正负,取出M再加1得到一个1.xxxx,然后通过公式(-1)^S * M * 2^E
特殊情况:
当E位全0:
当E为全0的时候,在float下,E就是-127;在 double 下,E就是-1023,那么2^E就是一个很小的数,接近0
当E为全1:
当E为全1时,E就是一个很大的数,2^E就会使这个浮点数接近无穷大。
现在我们来分析一下开头的例子:
#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;
}
9 的原码是0000 0000 0000 0000 0000 0000 0000 1001
32位的float,S是0,E是取八位 0000 0000 ,M是000 0000 0000 0000 0000 1001,由于E为全0,所以浮点数无限接近0。
9.0 用浮点数的公式表示:先算出M来,9.0 转化为二进制 1001.0,变为科学计数法就是1.0010 * 2^3 ,则M 为001,后面凑0,知道凑满23位,E等于3+127=130,化成二进制就是
1000 0010 ,由于是整数,所以符号位取0。
所以在内存中9.0表示为:
0100 0001 0001 0000 0000 0000 0000 0000
由于要进行整数打印,将上面一串二进制直接翻译成整数,拿计算机一算:

结果就是我们打印的结果。
相关文章:
数据在内存的存储
整数在内存中的存储 我们来回顾一下,整数在计算机是以补码的形式进行存储的,整数分为正整数和负整数,正整数的原码、反码和补码是一样的,负整数的原码、反码和补码略有不同(反码是原码除符号位,其他位按位取…...
JavaScript之ES中的类继承与Promise
类 ES5中的类及继承 //人function Person(name,age){this.name name;this.age age;}Person.prototype.eat function () {console.log(this.name "eat");}//程序员,继承,人function Programmer(name,age,language){//构造函数继承Person.…...
浅析多模态大模型技术路线梳理
前段时间 ChatGPT 进行了一轮重大更新:多模态上线,能说话,会看图!微软发了一篇长达 166 页的 GPT-4V 测评论文,一时间又带起了一阵多模态的热议,随后像是 LLaVA-1.5、CogVLM、MiniGPT-5 等研究工作紧随其后…...
使用 Amazon SageMaker 微调 Llama 2 模型
本篇文章主要介绍如何使用 Amazon SageMaker 进行 Llama 2 模型微调的示例。 这个示例主要包括: Llama 2 总体介绍Llama 2 微调介绍Llama 2 环境设置Llama 2 微调训练 前言 随着生成式 AI 的热度逐渐升高,国内外各种基座大语言竞相出炉,在其基础上衍生出…...
牛客小白月赛86(D剪纸游戏)
题目链接:D-剪纸游戏_牛客小白月赛86 (nowcoder.com) 题目描述: 输入描述: 输入第一行包含两个空格分隔的整数分别代表 n 和 m。 接下来输入 n行,每行包含 m 个字符,代表残缺纸张。 保证: 1≤n,m≤10001 字符仅有 . 和 * 两种字符…...
MySQL的基础操作与管理
一.MySQL数据库基本操作知识: 1.SQL语句: 关系型数据库,都是使用SQL语句来管理数据库中的数据。 SQL,即结构化查询语言(Structured Query Language) 。 SQL语句用于维护管理数据库,包括数据查询、数据更新、访问控…...
Pytorch 中的forward 函数内部原理
PyTorch中的forward函数是nn.Module类的一部分,它定义了模型的前向传播规则。当你创建一个继承自nn.Module的类时,你实际上是在定义网络的结构。forward函数是这个结构中最关键的部分,因为它指定了数据如何通过网络流动。 单独设计 forward …...
四、C语言中的数组:如何输入与输出二维数组(数组,完)
本章的学习内容如下 四、C语言中的数组:数组的创建与初始化四、C语言中的数组:数组的输入与元素个数C语言—第6次作业—十道代码题掌握一维数组四、C语言中的数组:二维数组 1.二维数组的输入与输出 当我们输入一维数组时需要一个循环来遍历…...
基于python+vue智慧农业小程序flask-django-php-nodejs
传统智慧农业采取了人工的管理方法,但这种管理方法存在着许多弊端,比如效率低下、安全性低以及信息传输的不准确等,同时由于智慧农业中会形成众多的个人文档和信息系统数据,通过人工方法对知识科普、土壤信息、水质信息、购物商城…...
好用的GPTs:指定主题搜索、爬虫、数据清洗、数据分析自动化
好用的GPTs:指定主题搜索、爬虫、数据清洗、数据分析自动化 Scholar:搜索 YOLO小目标医学方面最新论文Scraper:爬虫自动化数据清洗数据分析 点击 Explore GPTs: Scholar:搜索 YOLO小目标医学方面最新论文 搜索 Scho…...
使用Qt自带windeployqt打包QML的exe
1.在开始菜单输入CMD找到对应的Qt开发版本,我的是Qt5.15.2(MinGW 8.1.0 64-bit)。 2.在控制台输入如下字符串,格式为 windeployqt exe绝对路径 --qmldir 工程的绝对路径 如下是我的打包代码。 我需要打包的exe的绝对路径 D:\Prj\Code\Demo\QML\Ana…...
C代码快速傅里叶变换-分类和推理-常微分和偏微分方程
要点 C代码例程函数计算实现: 线性代数方程解:全旋转高斯-乔丹消元,LU分解前向替换和后向替换,对角矩阵处理,任意矩阵奇异值分解,稀疏线性系统循环三对角系统解,将矩阵从完整存储模式转换为行索…...
计算机组成原理 双端口存储器原理实验
一、实验目的 1、了解双端口静态随机存储器IDT7132的工作特性及使用方法 2、了解半导体存储器怎样存储和读出数据 3、了解双端口存储器怎样并行读写,产生冲突的情况如何 二、实验任务 (1)按图7所示,将有关控制信号和和二进制开关对应接好,…...
[音视频学习笔记]六、自制音视频播放器Part1 -新版本ffmpeg,Qt +VS2022,都什么年代了还在写传统播放器?
前言 参考了雷神的自制播放器项目,100行代码实现最简单的基于FFMPEGSDL的视频播放器(SDL1.x) 不过老版本的代码参考意义不大了,我现在准备使用Qt VS2022 FFmpeg59重写这部分代码,具体的代码仓库如下: …...
GPT-5可能会在今年夏天作为对ChatGPT的“实质性改进”而到来
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
官宣|阿里巴巴捐赠的 Flink CDC 项目正式加入 Apache 基金会
摘要:本文整理自阿里云开源大数据平台徐榜江 (雪尽),关于阿里巴巴捐赠的 Flink CDC 项目正式加入 Apache 基金会,内容主要分为以下四部分: 1、Flink CDC 新仓库,新流程 2、Flink CDC 新定位,新玩法 3、Flin…...
部署单节点k8s并允许master节点调度pod
安装k8s 需要注意的是k8s1.24 已经弃用dockershim,现在使用docker需要cri-docker插件作为垫片,对接k8s的CRI。 硬件环境: 2c2g 主机环境: CentOS Linux release 7.9.2009 (Core) IP地址: 192.168.44.161 一、 主机配…...
Django日志(三)
内置TimedRotatingFileHandler 按时间自动切分的log文件,文件后缀 %Y-%m-%d_%H-%M-%S , 初始化参数: 注意 发送邮件的邮箱,开启SMTP服务 filename when=h 时间间隔类型,不区分大小写 S:秒 M:分钟 H:小时 D:天 W0-W6:星期几(0 = 星期一) midnight:如果atTime未指定,…...
【吾爱破解】Android初级题(二)的解题思路 _
拿到apk,我们模拟器打开看一下 好好,抽卡模拟器是吧😀 jadx反编译看一下源码 找到生成flag的地方,大概逻辑就是 java signatureArr getPackageManager().getPackageInfo(getPackageName(), 64).signaturesfor (int i 0; i &l…...
富格林:谨记可信计策安全做单
富格林悉知,现货黄金由于活跃的行情给投资者带来不少的盈利的机会,吸引着众多的投资者进场做单。但在黄金投资市场中一定要掌握可信的投资方法,提前布局好策略,这样才能增加安全获利的机会。不建议直接进入市场做单,因…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
