大小端字节序问题
1.大小端定义
大端存储模式:是指数据的低位字节序保存在内存的高地址中,而数据的高位字节序保存在内存的低地址中
小端存储模式:是指数据的低位字节序保存在内存的低地址中,而数据的高位字节序保存在内存的高地址中
例如:16bit宽的数0x0001在CPU内存中的存放方式(假设从地址0x4000开始存放):
内存地址 | 0x4000 | 0x4001 |
---|---|---|
存储内容(大端) | 0x00 | 0x01 |
存储内容(小端) | 0x01 | 0x00 |
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
2.为什么会有大小端之分
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
3、如何去判断机器是大端模式还是小端模式?
1 ) 代码实现 :编译环境 VC++6.0 结果输出为 小端存储
#include "stdafx.h"
bool IsBigEndian1()
{
int a = 1; //00 00 00 01
//通过将int强制类型转换成char单字节,通过判断起始存储位置。即等于 取b等于a的低地址部分
char b = *(char *)&a;
/*
char b = *(char*)&a;这句话到底干了什么事呢?详解:
&a是通过'&'取地址符获取到了a的地址或者可以认为是个指向int类型数据的指针
(char *)&a 则把&a强制转换成 char *类型的指针,本句重点就是这个时候发生了截断!
<因为还未深入学习指针所以此处对为何发生截断不予详细解释,等后续系统学习后再做补充>
截断后,指针(char *)&a 内存放的是存放‘1’的低地址,也就是说此处指向的数值 即b仅为原
始数据的一部分。
因为已经确定 是低地址,所以可以通过此处地址指向的数值来判断此环境的存储模式是大端还是小端
如果b = 0 即 低地址存放高位数据 则为大端模式
如果b = 1 即 低地址存放低位数据 则为小端模式
*/
//printf("b=%0x\n",b); 此句如果被注释 将会输出 b=34 以此更直观的看到效果
if( b == 0)
{
return true;
}
return false;
}
int main(int argc, char* argv[])
{
if(IsBigEndian1()==true)
{
printf("大端存储\n");
}
else
{
printf("小端存储\n");
}
return 0;
}
2)联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性可以轻松地获得了CPU对内存采用Little-endian还是 Big- endian模式读写:
算法思路:定义一个联合体,根据联合体成员起始地址相同巧妙的访问到了第一个字节地址的数据。
联合体类型特点:
#include "stdafx.h"
/*
联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性
可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写:
*/
bool IsBigEndian2()
{
union NUM
{
int a;
char b;
}num;
num.a = 0x1234;
if( num.b == 0x12 )
{
return true;
}
return false;
}
int main(int argc, char* argv[])
{
if(IsBigEndian2()==true)
{
printf("Big-endian\n");
}
else
{
printf("Little-endian\n");
}
return 0;
}
4.常见字节序:
常见CPU的字节序
Big Endian : PowerPC、IBM、Sun、C51
Little Endian : x86、DEC、ARM(MCU)
ARM既可以工作在大端模式,也可以工作在小端模式。
常见文件的字节序
Adobe PS – Big Endian
BMP – Little Endian
DXF(AutoCAD) – Variable
GIF – Little Endian
JPEG – Big Endian
MacPaint – Big Endian
RTF – Little Endian
另外,在C语言中,默认是小端(但在一些对于单片机的实现中却是基于大端,比如Keil 51C),Java是平台无关的,默认是大端。在网络上传输数据普遍采用的都是大端。
转自这里(有改动):https://blog.youkuaiyun.com/lijian2017/article/details/109452091