引文
在开始正文之前,我想先问一下大家,内存中是怎样存放一个数的?当然啊,我这里问的不是数据存储的形式(比如整数存原码,负数存补码),而是一个数据存放的顺序
我们先看下面这个例子,当我们看看当把十六进制函数0x11223344存进内存中会是怎么样的。
我们看这个数低位44,高位33,再高位22,再高位11(注意44 、33、22、11各占一个字节,44地址0x0078F20,33地址...21,22地址...22,11地址...23),而我们看到这个数在内存中是倒着放的。为什么呢?接下来我讲引入大小端概念,为大家解答。
大小端介绍
(1)什么是大端小端
大小端全称大小端字节序存储,分为大端字节序存储和小端字节序存储。为什么叫字节序呢?就是以字节为单元来排它的循序。
在学习大小端存储之前,我们必须了解几个概念,
(1)我们要知道一个十六进制位能转换4个二进制位,那两个十六进制位就能转换8个二进制位,也就是一个字节(11 、 22 、 33 、44)。
(2)其中44是a中最低位的一个数据,11是a中最高位的一个数据。
在内存中,a有两种存储方式。
当我们把低位字节处的数据(44)放到高地址置处,把高位字节处的数据(11)放到低地址处,这种存储方式就是大端存储。反之就是小端存储。
如下图所示
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。
(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)笔试题讲解
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。(10分)
这是2015百度系统工程师笔试题,第一问咱们已经所过了,忘记的小伙伴可以回去再看一遍。
第二问我们可以用C语言来判断机器的大小端字节序。
首先我们知道一个数在内存中存储是第一个字节的数不相同,所以我们只需要判断内存中第一个字节就能判断大小端字节序。
我们先定义一个变量并赋值为1(1比较容易判断),1的十六进制位0x00000001,所以我们能判断00为大端字节处数据,01为小端字节处数据
如下在内存中的两种存储方式,如果我们那第一个字节是0那就是大端,如果是1那就是小端。
问题已经分析完了,接下来就该实现代码了。但是我们如果在四个字节里面取一个字节呢?
不知道大家了解char*字符型指针吗,char*指针解引用访问一个字节,我们可以借此把a的地址强制转换成char*保存在一个char*指针,解引用指针就能取出第一个字节了。
代码实现如下:
#include<stdio.h> int main() { int a = 1; //000000000000000000000001 //0x 00 00 00 01 char* p = (char*)&a; if (*p == 1) { printf("小端\n"); } else { printf("大端\n"); } return 0; }
到此本题结果就出来了。但是对我们来说得出结果还没有结束,我们需要等优等的代码。
首先这个代码是一次性的呀,如果别人想用的话就用不了了,所以我们可以把大小端判断代码封装成一个函数,这样别只要调用函数就能知道电脑是大端还是小端了。
同时我们最后不要在函数内打印,因为我们也不知道别人是否要打印结果,所以我们可以返回1代表是小端,返回0代表是大端。
到这有人可能发现了,这个代码还可以再简化一下。我们看*p,如果*p为1就返回1,那我们何不就返回*p呢,而*p是从那个地方获取的值呢?是*(char*)&a
所以我们直接return *(char*)&a
到此代码优化就完毕了。
int check_sys() { int a = 1; char* p = (char*)&a; if (*p == 1) { return 1;//小端 } else { return 0;//大端 } }
int check_sys() { int a = 1; return *(char*)&a; }
以上就是大小端字节序的讲解,有错误的地方希望大家能批评指正,别忘了点赞👍+收藏⭐️哦