大小端对齐

不同的 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值