概述
对齐访问就是当我们定义了一个2字节的变量,编译器可能会给我们分配4个字节,另外2个字节被闲置。对齐访问与非对齐访问是编译器对效率与资源权衡后的结果。非对齐访问物理内存是支持的,但是效率低,对齐访问效率高,所以编译器会使用对齐访问。
非对齐访问过程
第一步:读涉及内存的第一个字节,
第二步:读涉及内存的第二个字节;
第三步:清除第一字节的无关位,
第四部:清除清除第二字节的无关位,
第5步:将第1字节与第二字节组合。所以效率极低。
对齐访问
只需要1次读出即可,即使浪费空间也无所谓。如下
struct
{
int a;//占用4字节,不用考虑填充
char b; //占用2字节,考虑下面是2字节,所以自己填充1个字节;
short c; //占用2字节,考虑下面要8字节,所以填充6个字节
double e; //占用8字节
}对齐方法
- 每种数据类型都有自己的对齐规则,如char 1字节对齐,起始地址必须是1的整数倍;short 2字节对齐,起始地址必须是2的整数倍;int 4字节对齐,起始地址必须是4的整数倍。
- 不同类型在一起需要对齐时,首先满足自己的起始地址对齐,如果前面结束的地址没有对齐,不满足本变量的对齐起始地址,编译器会自动在前面填充。
指定对齐
在变量定义区域的前添加 #pragma pack(x);结束时添加#pragma pack();x是对齐数;结构体内部元素对齐,使用得较少。
取消对齐
__attribute__ ((packed))取消对齐;注意是双下划线,作用域只针对申明的结构体,其它的不受影响;在定义类型时添加有效,定义变量时添加无效;
struct best
{
double e; //8
char table[11];
} __attribute__ ((packed)) x;整个结构体对齐
__attribute__((aligned( n ))) 指定整个结构体对齐位,与成员无关。
struct best
{
double e; //8
char table[11];
} __attribute__ ((aligned(1024))) x; //offsetof宏
- 语法:#define offsetof(TYEP,MEMBER) (int) (&((TYEP *)0) -> MEMBER);
- 作用:计算结构TYEP体成员MEMBER基于TYEP起始地址的偏移量;返回偏移地址。
- 释义: (TYEP *)0 ; //将地址0强制转换成TYPE结构体类型的指针;
&((TYEP *)0) ->MEMBER; //基于0地址,取MEMBER的地址,即MEMBER偏移地址;
(int) (&((type *)0 ->member)); //将取到的地址强制转换成int;
typeof(a):typeof是c语言的关键字;作用是用来提取变量的类型;- 作用:通过给定的结构体成员变量,计算结构体的起始地址;
- 用法:container(ptr,type,member); //ptr 指向结构体成员member的指针;返回值是指向结构体的起始地址。
- 原型:
#define container(ptr,type,member) typeof( ((type *)0)->member) *__mptr = ptr; \
(type *) ( (char *)__mptr – offset(type,member) )- 释义:
typeof( (type *)0 ->member ) *__mptr = ptr; //使用c语言的关键字typeof获得结构体成员member类型,并定义一个该类型的指针__mptr,并且将传参进行赋值。
(type *) ( char *) __mptr -offset(type,member); //offset宏返回的是偏移量,是基于8位地址的,因此需要将__mptr先转换成char指针,该指针存的就是地址,使用地址 – 偏移量就能获得起始地址。返回时转换成输入的结构体类型
获取结构体的起始地址
char *add = ((char *)(& x.e)) - offsetof(struct best,e);- 用&取地址符号获得成员的地址;
- offsetof计算成员的偏移地址;
- 成员地址 – 偏移地址 = 起始地址;
版权声明:本文为m0_60073820原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。