什么是大小端?
高地址,低地址是针对内存地址而言,高位,低位是针对数据类型的bit位的高低而言。
- 大端(Big-Endian):高地址存放低位
- 小端(Little-Endian):高地址存放高位
大小端影响了什么?
当基本数据类型占用字节数超过了1字节后,大小端决定了数据按照什么顺序存储在内存里
既然字节数超过了1个字节才有影响,那么就会一个疑问,char型数据占用字节数为1个字节,那么char型数据在大小端的模式下,没有什么不同。
大小端只针对基本数据类型
大小端只针对基本数据单元类型,那么什么是基本数据类型单元呢,char, int, float, double,那什么不是基本数据类型呢?例如:数组,结构体,联合等等。需首先找出基本数据类型,明确数据占用字节数以及高位,低位情况
明确变量地址始终指向变量的低地址
根据大小端的特性来套表格
基本数据类型
内存地址存储的最小数据大小就是字节,例如一个变量char temp的地址0x10000000,temp值为0x55,由于char类型只占用一个字节,那么temp变量就只占用0x10000000这个内存地址,不会占用其他内存地址,假如变量是个int型呢 占用的字节数可能是4字节,这时候就有了大小端存储
例1(基本数据类型):int temp = 0x12345678;
假设 temp 的地址为 0x10000000 ,按照上面的分析步骤来拆分解析
int型占用字节数为4字节,将数据按照字节为单位的高位,低位分解如下:0x12(高位),0x34,0x56 ,0x78 (低位)
由1点可知,基本数据类型占用内存为4字节,所以内存地址范围为 0x10000000~ 0x10000003
根据大小端的特性来套表格如下
大端模式
内存地址 内存值 步骤
0x10000000 0x12 4.依次取值
0x10000001 0x34 3.依次取值
0x10000002 0x56 2.依次取值
0x10000003 0x78 1.高地址存放低位
小端模式
内存地址 内存值 步骤
0x10000000 0x78 4.依次取值
0x10000001 0x56 3.依次取值
0x10000002 0x34 2.依次取值
0x10000003 0x12 1.高地址存放高位
数组
- 数组的元素布局顺序是固定的,从低地址到高地址。
例2(数组):short int temp[2] = {0x1234,0x5678};
假设 temp 的地址为 0x10000000 ,按照上面的分析步骤来拆分解析
short int型占用字节数为2字节,将数据按照字节为单位的高位,低位分解如下:0x12(高位),0x34(低位),0x56 (高位),0x78 (低位)
由1点可知,基本数据类型占用内存为2字节,但是由两个元素,所以内存地址范围为 0x10000000~ 0x10000003
根据大小端的特性来套表格如下
大端模式
内存地址 内存值 步骤
0x10000000 0x12 2.依次取值
0x10000001 0x34 1.高地址存放低位
0x10000002 0x56 4.依次取值
0x10000003 0x78 3.高地址存放低位
小端模式
内存地址 内存值 步骤
0x10000000 0x34 2.依次取值
0x10000001 0x12 1.高地址存放高位
0x10000002 0x78 4.依次取值
0x10000003 0x56 3.高地址存放高位
结构体
- 结构体的成员布局顺序也是固定的,按定义的顺序从低地址到高地址。
//C code: get CPU big endian or small endian
#include <stdio.h>
union TEST{
unsigned char aa[4];
unsigned int bb;
};
int main()
{
union TEST test;
test.aa[0] = 0x01;
test.aa[1] = 0x02;
test.aa[2] = 0x03;
test.aa[3] = 0x04;
if (test.bb == 0x01020304)
printf("it's big endiam!\r\n");
else if (test.bb == 0x04030201)
printf("it's small endiam!\r\n");
else
printf("unknow endiam system! 0x1234 VS 0x%x\r\n", test.bb);
return 0;
}
- 联合体和结构体的成员变量的内存都是按照成员变量顺序从低地址到高地址分布。可以利用联合体的这些特性来检测系统使大端模式还是小端模式。
BOOL IsBigEndian()
{
union NUM
{
int a;
char b;
}num;
num.a = 0x1234;
if( num.b == 0x12 )
{
return TRUE;
}
return FALSE;
}
位域
-
小端模式,先定义的位域存储在低地址低位,后定义的位域存储在高地址中高位
-
大端模式,先定义的位域存储在高地址中高位,后定义的位域存储在低地址低位中
-
存在位域的情况下,小端模式下先定义的位域从LSB(最低有效位)开始,大端模式下先定义的位域从MSB(最高有效位)开始,先定义的位域因大小端情况会表示最高位或者最低位。
例3(位域结构体):
struct {
int b1:1;
int b2:2;
int b3:3;
int b4:4;
char b5:5;
}
temp = {.b1=1, .b2=2, .b3=3, .b4=4, .b5=5 };
假设 temp 的地址为 0x10000000 ,按照上面的分析步骤来拆分解析
int型占用字节数为4字节,char型占用字节数为1字节
基本数据类型占用内存为4字节+1字节,所以内存地址范围为 0x10000000~ 0x10000004
大端下位域分布
首先分析位域情况
- 大端下temp的int值位域分布如下 int值为0xCD000000
bit位 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
b1 b2 b2 b3 b3 b3 b4 b4 b4 b4
bit值 1 1 0 0 1 1 0 1 0 0 - - - - - - - - - - - - - - - - - - - - - -
大端下temp的char值位域分布如下 char值为0x28
bit位 7 6 5 4 3 2 1 0
b5 b5 b5 b5 b5
bit值 0 0 1 0 1 - - -
大端模式下将数据按照字节为单位的高位,低位分解如下:0xCD(高位),0x00,0x00,0x00(低位),0x28(字节)
内存地址 内存值 步骤
0x10000000 0xCD 4.依次取值
0x10000001 0x00 3.依次取值
0x10000002 0x00 2.依次取值
0x10000003 0x00 1.高地址存放低位
0x10000004 0x28 5.高地址存放低位
小端下位域分布
- 小端下temp的int值位域分布如下 int值为0x0000011D
bit位 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
b4 b4 b4 b4 b3 b3 b3 b2 b2 b1
bit值 - - - - - - - - - - - - - - - - - - - - - - 0 1 0 0 0 1 1 1 0 1
小端下temp的char值位域分布如下 char值为0x05
bit位 7 6 5 4 3 2 1 0
b5 b5 b5 b5 b5
bit值 - - - 0 0 1 0 1
小端模式下将数据按照字节为单位的高位,低位分解如下:0x00(高位),0x00,0x01,0x1D(低位),0x05(字节)
小端模式
内存地址 内存值 步骤
0x10000000 0x1D 4.依次取值
0x10000001 0x01 3.依次取值
0x10000002 0x00 2.依次取值
0x10000003 0x00 1.高地址存放高位
0x10000004 0x05 5.高地址存放高位
根据大小端不一样所需要定义的位域结构体也不一样
bit位 7 6 5 4 3 2 1 0
(reserved 3bit) (id 2bit) (connect 1bit)(status 2bit)
bit值 - - - - - - - -
struct {
#if __IsBigEndian__
uint8_t reserved:3;
uint8_t id:3;
uint8_t connect:1;
uint8_t status:2;
#else
uint8_t status:2;
uint8_t connect:1;
uint8_t id:3;
uint8_t reserved:3;
#endif
} data;