栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > C/C++/C#

什么是“大小端字节序”存储模式?

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

什么是“大小端字节序”存储模式?

本文以C语言实现,主要通过例题+说明的模式讲解存储模式:大小端字节序。


目录

引言

一、大小端介绍

1. 大端字节序与小端字节序的概念

2. 为什么会有大小端之分?

3.一道和字节序相关的例题

题干

思路 

二、如何设计一个小程序判断当前机器的字节序?

百度2015年系统工程师笔试题

题干

解题


引言

我们知道,当编译器执行 “创建变量” 这一代码时,会在内存中开辟空间相应的空间来存储变量值。而对于整型变量而言,变量值又是以二进制补码的形式存放的。

对于正整数而言,它的补码 = 原码 = 反码;

对于负整数而言,它的补码 = 原码按位取反(就是反码) + 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. 为什么会有大小端之分? 这是因为在计算机系统中,我们以字节为单位,每个地址单元都对应着一个字节,一个字节为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 处理器还可以由硬件来选择是大端模式还是小端模式。

3.一道和字节序相关的例题

题干

在小端机器中,下面代码输出的结果是:

#include 

int main()
{
	int a = 0x11223344;
    char *pc = (char*)&a;
    *pc = 0;
    printf("%xn", 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年系统工程师笔试题 题干 请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。( 10 分)

解题

概念部分同上,在此不再赘述。

代码部分:

1. 要检测某一机器是大端还是小端其实并不难,我们可以直接用int类型的1来检测。

2. 1在内存中的二进制补码为:00000000  00000000  00000000  00000001

    也就是说,我们只需要把首个内存单元的值取出来看看是0还是1,就能判断它是大端还是小端。

因为如果是大端,则“高数位存在低地址”,我们取出最低地址的值,应当是最高数位上的数00000000;而若是小端,则“低数位存在低地址”,依然取出最低地址的值,应当是00000001

 依照该思路,有以下代码:

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

当然,也可以用共用体来实现检查,这是更为便捷的一种方式: 

int check_sys()
{
     union
     {
         int i;
         char c;
     }un;
     un.i = 1;
     
    return un.c; 
}

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1036987.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号