结构体的对齐访问

描述:在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。从理论上讲,对于任何变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列,而不是简单地顺序排列,这就是内存对齐。

  1. 举列说明什么是结构体对齐访问
    1.1 结构体中元素的访问其实本质上还是用指针方式,结合这个元素在整个结构体中的偏移量和这个元素的类型来进行访问的。
    1.2 实际上结构体的元素的偏移量比我们上节讲的还要复杂,因为结构体要考虑元素的对齐访问,所以每个元素时间占的字节数和自己本身的类型所占的字节数不一定完全一样。(譬如char c实际占字节数可能是1,也可以是2,也可能是3,也可以能4····)
    1.3 一般来说,我们用 . 的方式来访问结构体元素时,我们是不用考虑结构体的元素对齐的。因为编译器会帮我们处理这个细节。但是因为C语言本身是很底层的语言,而且做嵌入式开发经常需要从内存角度,以指针方式来处理结构体及其中的元素,因此还是需要掌握结构体对齐规则

  2. 结构体为何要对齐访问
    2.1 结构体中元素对齐访问主要原因是为了配合硬件,也就是说硬件本身有物理上的限制,如果对齐排布和访问会提高效率,否则会大大降低效率.
    2.2 内存本身是一个物理器件(DDR内存芯片,SoC上的DDR控制器),本身有一定的局限性:如果内存每次访问时按照4字节对齐访问,那么效率是最高的;如果你不对齐访问效率要低很多。
    2.3 还有很多别的因素和原因,导致我们需要对齐访问。譬如Cache的一些缓存特性,还有其他硬件(譬如MMU、LCD显示器)的一些内存依赖特性,所以会要求内存对齐访问。
    2.4 对比对齐访问和不对齐访问:对齐访问牺牲了内存空间,换取了速度性能;而非对齐访问牺牲了访问速度性能,换取了内存空间的完全利用。

  3. 结构体对齐的规则和运算
    3.1 编译器本身可以设置内存对齐的规则,有以下的规则需要记住:
    第一个:32位编译器,一般编译器默认对齐方式是4字节对齐。
    3.2 结构体对齐要考虑:结构体整体本身必须安置在4字节对齐处,结构体对齐后的大小必须4的倍数
    3.3 结构体中每个元素本身都必须对其存放,而每个元素本身都有自己的对齐规则。
    3.4 编译器考虑结构体存放时,以满足以上2点要求的最少内存需要的排布来算。

  4. gcc支持但不推荐的对齐指令:#pragma pack() #pragma pack(n) (n=1/2/4/8)
    4.1 #pragma是用来指挥编译器,或者说设置编译器的对齐方式的。编译器的默认对齐方式是4,但是有时候我不希望对齐方式是4,而希望是别的(譬如希望1字节对齐,也可能希望是8,甚至可能希望128字节对齐)。
    4.2 常用的设置编译器对齐命令有2种:第一种是#pragma pack(),这种就是设置编译器1字节对齐(有些人喜欢讲:设置编译器不对齐访问,还有些讲:取消编译器对齐访问);第二种是#pragma pack(4),这个括号中的数字就表示我们希望多少字节对齐。
    4.3 我们需要#prgama pack(n)开头,以#pragma pack()结尾,定义一个区间,这个区间内的对齐参数就是n。
    4.4 #prgma pack的方式在很多C环境下都是支持的,但是gcc虽然也可以不过不建议使用。
    举列说明:

// 这个代表是1字节对齐设置
#pragma pack(1)

/* Scatter Gather List Entry */
typedef struct TAG_TW_SG_Entry {
     dma_addr_t address;
     u32 length;
} TW_SG_Entry;

/* This struct is a union of the 2 command packets */
typedef struct TAG_TW_Command_Full {
 TW_Command_Apache_Header header;
 union {
  TW_Command oldcommand;
  TW_Command_Apache newcommand;
 } command;
} TW_Command_Full;

/* Response queue */
typedef union TAG_TW_Response_Queue {
 u32 response_id;
 u32 value;
} TW_Response_Queue;

#pragma pack()


  1. gcc推荐的对齐指令__attribute__((packed)) attribute((aligned(n)))
    5.1 attribute((packed))使用时直接放在要进行内存对齐的类型定义的后面,然后它起作用的范围只有加了这个东西的这一个类型。packed的作用就是取消对齐访问。
    5.2 attribute((aligned(n)))使用时直接放在要进行内存对齐的类型定义的后面,然后它起作用的范围只有加了这个东西的这一个类型。它的作用是让整个结构体变量整体进行n字节对齐(注意是结构体变量整体n字节对齐,而不是结构体内各元素也要n字节对齐)
    举例说明:
struct stu{

   char sex;

   int length;

   char name[10];

  }__attribute__ ((aligned (1))); 

// 转自朱老师物联网大课堂

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值