C语言内存对齐规则

为什么要内存对齐,内存对齐的根本原因是由于处理器访问内存的方式决定的,以ARM 32位处理器为例,地址总线为32位,处理器访问的内存地址只能是4的倍数,如果一个int 类型的变量占用内存地址0、1、2、3字节空间,则处理器从0地址一次就可将数据去除,如果该int类型从地址空间2开始存储,占内存地址2、3、4、5字节空间,则处理器需要先访问0地址空间取出数据的高8位,再访问4地址空间取出数据的低8位,让后再将高低位数据组合在一起,这样的话处理器的效率就慢了一倍。因此我们在定义变量使用时,编译器会自动使分配的变量进行4字节对齐,以提高编译器的效率。

我门看一下,编译器字节对齐的相应规则:

1. 对于int、char、short、float、double等单个的数据类型,不需要我门去关心,编译器在分配空间时,就已经保证是4字节对齐。

2. 对于结构体、联合、类等自定义数据类型,编译器在分配内存空间时,会对结构体进行填充,保证结构体内部成员的字节边界对齐和结构体整体内存空间的对齐。毫无疑问这样会提高效率,但是有些时候我们不希望结构体进行对齐,例如我使用结构体定义了一帧数据.

struct message

{

unsigned char type;

unsigned short len;

unsigned int data;

}Tmsg;

struct Tmsg msg;

像上述的结构体,编译器在分配内存空间时,会对结构体进行填充,结构体的实际长度并不是1+2+4 = 7,而是2+2+4 = 8;在type成员和len成员之间编译器会添加一个字节的填充,加入我把这帧数据通过网络发到服务器上send(ip,port,&msg,sizeof(Tmsg)),那么服务器可能就会收到带有填充的数据帧,在进行数据解析时就会出现错误。这时候我们就需要去指定结构体进行一字节对齐。

#pragma pack(1)

struct message

{

unsigned char type;

unsigned short len;

unsigned int data;

}Tmsg;

#pragma pack()

3. 数组内存对齐

编译器自身的malloc函数分配的内存空间时8字节对齐的,但是我们自定义的内存分配函数是无法保证内存对齐的,需要我们在内存池数组前添加__align(4),来保证数据空间的内存对齐。

__align(4) u8 mem1base[MEM1_MAX_SIZE];

这点是很重要的特别是使用DMA进行数据传输时,如果使用了内存未对齐的内存,可能会出问题。

4. 自定义数据类型(结构体等)编译器分配内存对齐规则

结构体成员对齐规则:结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

结构体自身对齐规则:结构整体的对齐,则按照结构体中最大的数据成员和#pragma pack指定值 之间,较小的那个进行。

5. 结构体内存对齐规则修改:我们可以使用__align(n)(常用于数组内存对齐修饰),#pragma pack(n)(常用于结构体内存对齐修饰)在改变编译器的内存对齐规则。

方法一:
使用#pragma pack(n),指定c编译器按照n个字节对齐;
使用#pragma pack(),取消自定义字节对齐方式。

方法二:
__attribute(aligned(n)),让所作用的数据成员对齐在n字节的自然边界上;如果结构中有成员的长度大于n,则按照最大成员的长度来对齐;
__attribute((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

比如:

typedef struct

{

  ...

}__attribute__((aligned(4))) param_t;

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值