当前位置:网站首页>什么是“大小端字节序”存储模式?
什么是“大小端字节序”存储模式?
2022-08-10 04:25:00 【碳基肥宅】
本文以C语言实现,主要通过例题+说明的模式讲解存储模式:大小端字节序。
目录
引言
我们知道,当编译器执行 “创建变量” 这一代码时,会在内存中开辟空间相应的空间来存储变量值。而对于整型变量而言,变量值又是以二进制补码的形式存放的。
对于正整数而言,它的补码 = 原码 = 反码;
对于负整数而言,它的补码 = 原码按位取反(就是反码) + 1;
例如,当语句 int a = 500 被执行时,内存中会开辟 4字节(即32bit)的空间存储整数20的二进制补码(00000000 00000000 00000001 11110100)。同时,我们也知道,内存中的每一个存储单元的大小为 1字节(8bit)。
那么此时问题来了:int a = 500所占的总空间是4字节,然而每一个内存单元只存的下1字节的数据,换句话说,每一个整型数据需要4个存储单元才能存的下——那么,这4个存储单元在内存中到底是如何分布的呢?
是像数组一样,用来存储数据的4个内存单元彼此之间连续开辟,还是物理空间上其实并不连续、只是解析数据时把4个单元中的数据“拼”到一起,还原出连续的整型数呢?

这个问题,本质上是数据在内存中的存储模式问题。这就关系到我们今天要介绍的重点:大端数据存储模式或小端数据存储模式(即大端字节序与小端字节序)。
我们打开编译器vs2019的内存监视,可以从监视窗口看到数值在内存中的存储情况(显示为16进制)。
注意:32位下,
20的16进制补码为:00 00 00 14
-10的十六进制补码为:ff ff ff f6

两个16进制位恰好是一个字节8bit。我们将视图调整为每行显示4个字节(即一个int,这样看得更清晰),于是可以发现,在内存中数据似乎是“倒着存”的。00 00 00 14在内存中的存储显示为了14 00 00 00.
事实上,这并不叫做“倒着存”,这正是我们上面提到过的:小端字节序的存储模式。在阅读完本文后,我们就能明白。
一、大小端介绍
当一个数值的大小超过 1字节 ,那么它要存到内存中,字节与字节之间就有存储顺序的问题。这个顺序称之为字节序。

以int类型为例。
理论上来说,即使存储一个int型数据的4个存储单元不连续,甚至天南海北,只要最终解析时能还原成一个正常的数即可。但是这么做属实没有必要:计算机中存储肯定是采用最便捷的存储方式,那就是连续存储,一个整型的4个字节空间挨在一块儿。
这时要考虑的问题便是,这四个挨在一块的存储空间,是由低地址向高地址存储,还是由高地址向低地址存储?
1. 大端字节序与小端字节序的概念
小端字节序:把一个数值的低位字节内容存放在低地址处;高位字节内容存放在高地址处。(低位存低地址,高位存高地址)。
大端字节序:把一个数值的低位字节内容存放在高地址处;高位字节内容存放在低地址处。(低位存高地址,高位存低地址)。
例如,要存储一个十六进制数 0x11223344。该数中右端是低数位,左端是高数位(类比十进制数,十进制数10里面0是个位更低,1是十位更高)。
小端存储情况如下:

小端存储模式下,若取出该int型数据的首地址内容会发现,存的其实是0x44。
而大端存储情况如下:

以上就是对大小端存储模式的理解。
至于实际中如何存储的,还取决于具体编译器的选择。现在大部分的编译器选择的是小端存储模式,也就是我们上面看到的“倒着存”。
这时再参照引言中的例子,应该能对这两种存储模式有一个较好的理解了。
2. 为什么会有大小端之分?
3.一道和字节序相关的例题
题干
在小端机器中,下面代码输出的结果是:
#include <stdio.h>
int main()
{
int a = 0x11223344;
char *pc = (char*)&a;
*pc = 0;
printf("%x\n", a);
return 0;
}思路
本题中的数值与我们上面讨论的数值一样,应该不难理解:
1. char*类型的指针变量pc指向的只能指向char类型的空间。如果是非char类型的空间,则必须将该空间的地址强转为char*类型。
2. char *pc = (char*)&a; pc实际指向的是整形变量a的空间,即指针pc里放的是0x00405090,指向的值即0x44。
3. *pc=0,关键一步:究竟是将哪个存储单元中的值置零了?由首个单元中存储的内容可知,将0x44位置中内容改为了0。修改完成之后,a中内容为:0x11223300 (数值书写肯定是高数位在左,低数位在右)

二、如何设计一个小程序判断当前机器的字节序?
百度2015年系统工程师笔试题
题干
解题
概念部分同上,在此不再赘述。
代码部分:
1. 要检测某一机器是大端还是小端其实并不难,我们可以直接用int类型的1来检测。
2. 1在内存中的二进制补码为:00000000 00000000 00000000 00000001
也就是说,我们只需要把首个内存单元的值取出来看看是0还是1,就能判断它是大端还是小端。
因为如果是大端,则“高数位存在低地址”,我们取出最低地址的值,应当是最高数位上的数00000000;而若是小端,则“低数位存在低地址”,依然取出最低地址的值,应当是00000001

依照该思路,有以下代码:
#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;
}当然,也可以用共用体来实现检查,这是更为便捷的一种方式:
int check_sys()
{
union
{
int i;
char c;
}un;
un.i = 1;
return un.c;
}边栏推荐
猜你喜欢

万字总结:分布式系统的38个知识点

多元函数的3D可视化,终于被我总结出来了,数学真是太美了

Unity implements UI edge detection and drag-and-drop functions

LeetCode·1413.逐步求和得到正数的最小值·贪心

PID与ADRC

tensorflow分词深度学习——影评预测

2022年P气瓶充装操作证考试题库及模拟考试

RadiAnt DICOM Viewer 2022.1 Crack

What is the relationship between legal representative and shareholders?

2022G3 Boiler Water Treatment Exam Mock 100 Questions and Mock Exam
随机推荐
RK3568处理器体验小记
最新开源的面试笔记,天花板级别!
tensorflow分词深度学习——影评预测
qwt库的编译和使用
文献 | 关于心理活动符号学,你知道多少?
openvino 安装(01)
【Mindspore】【310推理】导入mindir文件出错
华为交换机配置日志推送
X书6.97版本shield-unidbg调用方式
Unity Shader 积雪效果
PHPCMS仿站从入门到精通,小白看这一套课程就够了
社区分享|货拉拉通过JumpServer纳管大规模云上资产
【OpenCV图像处理5】图像的变换
基于Nonebot2的qq机器人如何测试超管账号
释放高通量算力价值潜能 JASMINER持续领跑 Web3 市场
ZZULIOJ:1030: 判断直角三角形
2022华数杯思路分析
[crit] 23856#0: *101796511 stat()
mindspore gpu版本安装问题
【无标题】