不同的 CPU 有不同的字节序类型 这些字节序是指整数在内存中保存的顺序 这个叫做主机序
最常见的有两种
1 . Little endian :将低序字节存储在起始地址
2 . Big endian : 将高序字节存储在起始地址
网上有好多教程,但是不太好理解与记忆,下面讲解一下自己的理解。
LE little-endian
最符合人的思维的字节序
地址低位存储值的低位
地址高位存储值的高位
怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说
低位值小,就应该放在内存地址小的地方,也即内存地址低位
反之,高位值就应该放在内存地址大的地方,也即内存地址高位 右边是低位
BE big-endian
最直观的字节序
地址低位存储值的高位
地址高位存储值的低位
为什么说直观,不要考虑对应关系
只需要把内存地址从左到右按照由低到高的顺序写出
把值按照通常的高位到低位的顺序写出
两者对照,一个字节一个字节的填充进去
例子:在内存中双字 0x01020304(DWORD) 的存储方式
内存地址
4000 4001 4002 4003
LE 04 03 02 01
BE 01 02 03 04
例子:如果我们将 0x1234abcd 写入到以 0x0000 开始的内存中,则结果为
big-endian little-endian
0x0000 0x12 0xcd
0x0001 0x23 0xab
0x0002 0xab 0x34
0x0003 0xcd 0x12
x86 系列 CPU 都是 little-endian 的字节序 .
下面讲解一下在代码中实现大小端对齐的方法:
/*对齐实验代码定义*/
struct EA{
char a;
char b;
char c;
}__attribute__((packed)); /*以一个字节为单位,以代码空间换数据空间,不推荐*/
typedef struct EA EA_t;
//struct A A1;
EA_t EA1; // 与上句等价
struct A{
unsigned long a;
unsigned long b;
}__attribute__((aligned(4)));
typedef struct A A_t;
//struct A A1;
A_t A1; // 与上句等价
struct B{
char a;
char d;
unsigned long b;
unsigned short c;
}__attribute__((aligned(4)));
struct B B1;
struct C{
char a;
unsigned long b;
unsigned short c;
}__attribute__((aligned(4)));
//}__attribute__((aligned(2))); /*速度和代码量劣于32位对齐*/
//}__attribute__((packed)); /*以一个字节为单位,以代码空间换数据空间,不推荐*/
typedef struct C C_t;
C_t C1;
/*大小端 */
union myunion
{
int a;
char b;
};
// 如果是小端模式则返回1,大端模式则返回0
int is_little_endian(void)
{ int i=0;
union myunion u1;
u1.a = 0x12345678; // 地址0的那个字节内是0x78(小端)或者0x12(大端)
if(0x78 == u1.b)
i=1;
else if(0x12 == u1.b)
i=0;
return i;
}
int main(void)
{
/*查看帮助添加printf 重定向代码*/
printf("Hello World!\n");
/*——————————————————————————*/
/*对齐*/
EA1.a='a'; EA1.b='a'; EA1.c='a';
A1.a=0x01020304; A1.b=0x01020304;
B1.a='B'; B1.b=0x01020304;B1.c=0x0506;B1.d='B';// d的地址不是4字节?小端 Little Endian
C1.a='C';C1.b=0x01020304;C1.c=0x0506;
printf("结构体A1分配空间 = %d\n", sizeof( A1)) ;
printf("结构体B1分配空间 = %d\n", sizeof( B1)) ;
printf("结构体C1分配空间 = %d\n", sizeof( C1)) ;
/*——————————————————————————*/
/*大小端与Union*/
int i = is_little_endian();
if (i == 1)
{
printf("小端模式\n");
}
else
{
printf("大端模式\n");
}
}
上述代码用到了“__attribute__((aligned(4)))”,它指定结构体变量的最小对齐方式,以字节为单位,它使编译器在4字节边界上分配变量a,b,c,d。该指令告诉编译器将缓冲区放在一个四个字节的倍数的地址上。 在某些处理器上,这没有任何影响,在其他处理器上,如果你不是一次只读取一个字节而是读取2,4或8(16,32和64位)并且在某些处理器上它会加速内存访问甚至需要2,4或8字节访问(否则会发生总线错误)。
#include <stdio.h>
main()
{
struct A {
int a;
char b;
short c;
};
struct B {
char b;
int a;
short c;
};
#pragma pack (2) /*指定按2字节对齐*/
struct C {
char b;
int a;
short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐*/
#pragma pack (1) /*指定按1字节对齐*/
struct D {
char b;
int a;
short c;
};
#pragma pack ()/*取消指定对齐,恢复缺省对齐*/
int s1=sizeof(struct A);
int s2=sizeof(struct B);
int s3=sizeof(struct C);
int s4=sizeof(struct D);
printf("%d\n",s1);
printf("%d\n",s2);
printf("%d\n",s3);
printf("%d\n",s4);
}
输出:
8
12
8
7
修改代码:
struct A {
// int a;
char b;
short c;
};
struct B {
char b;
// int a;
short c;
};
输出:
4
4
说明未指定对齐方式时,默认是四字节对齐
参考:
https://www.cnblogs.com/ransn/p/5081198.html
https://blog.csdn.net/huangkangying/article/details/101195229