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