C语言字节对齐与GNU __attribute__、__align()__选项使用说明

1、什么是字节对齐?

对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好等于它长度的整数倍,他就被称做自然对齐。比如在32位cpu下,假设一个int 型变量iNum的地址为0x00000004或0x00000008,那它就是自然对齐的;但是如果iNum的地址为

0x0000 0006或0x0000 00009(假定从0x0000 0000 ---0x0000 0005内存存放的是其他数据),那么就不是自然对齐。

2、字节对齐的优缺点

优点:

 需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。而如果变量在自然对齐位置上,则只要一次就可以取出数据,因此提高了CPU访问数据的效率。

缺点:内存空间占用大,典型的以牺牲空间换取时间的做法。

3、为什么要使用字节对齐?

在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构、联合等)的数据单元。在结构中,编译器为结构的每个成员按其自然边界(alignment)分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐”. 比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除.

4、四个重要概念

(1)数据类型自身的对齐值: 对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
(2)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值
(3)指定对齐值:#pragma pack (value)时的指定对齐值value
(4)数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值

5、GNU __attribute__选项
  
GNU使用__attribute__选项来设置我们想要的内存字节对齐大小。__attribute__选项不属于标准C语言,它是GCC对C语言的一个扩展用法。例如,我们可以这样定义结构体:
  
  struct people{
   char sex;
   int length;
   char name[20];
  }__attribute__ ((aligned (1))); 
  struct people zhang_san,则sizeof(zhang_san)可以得到大小为25。
  上面的定义等同于
  struct people{
   char sex;
   int length;
   char name[20];
  }__attribute__ ((packed)); 
  struct stu zhang_san;此时sizeof(zhang_san)可以得到大小为25。如果去掉__attribute__ ((packed)),则sizeof(zhang_san)大小是40,需要补充15byte空间,结构体自身对齐。
   
  注:__attribute__((packed))的变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐。

6、调整C编译器的默认字节对齐方式

在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
(1)使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
(2)使用伪指令#pragma pack (),取消自定义字节对齐方式。

另外,还有如下的一种方式:
(1)__attribute__((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
(2)__attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

注:对齐属性的有效性会受到链接器(linker)的固有限制,即如果你的链接器仅仅支持8字节对齐,即使你指定16字节对齐,那么它也仅仅提供8字节对齐。

7、常见的使用字节对齐的代码编写风格

7.1、使用#pragma pack(n)

#pragma pack (4) /*指定按4字节对齐*/
struct test
{
        char b;
        int a;
        short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐*/

7.2、定义结构体时,如果确定其定义的所有变量都要做字节对齐,则可以直接在定义结构体时使用__attribute__ ((aligned (n))),例如:

struct people{
   char sex;
   int length;
   char name[20];
  }__attribute__ ((aligned (4))); 

按照四字节对齐,则使用struct people 定义的结构体变量zhang_san、li_si都是四字节对齐。

7.3、定义结构体时,如果确定其定义的部分变量才使用字节对齐,则可以如下操作:

struct people{
   char sex;
   int length;
   char name[20];
  }my_people; 

方式1:

my_people zhang_san __attribute__ ((aligned (4))); ----执行四字节对齐,

等价于:

(1)__attribute__ ((aligned (4)))  my_people zhang_san ;

(2)__attribute__ ((aligned (4)))

         my_people zhang_san ;

my_people li_si;---执行默认自身对齐

方式2:

#pragma pack (4) /*指定按4字节对齐*/

my_people zhang_san ;

#pragma pack () /*取消按4字节对齐*/

my_people li_si;---执行默认自身对齐

8、参考链接

https://www.cnblogs.com/ransn/p/5081198.html

 

 

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只特立独行的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值