字节对齐(C语言重点)
知识点解释:计算机内存空间都是按照byte划分的,理论上任何变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间排列,而不是一个接一个的排放。
一般win32 x86平台,每次分配都是以4字节的整数倍进行分配
对齐准则:
1.先了解四个概念
1):数据类型自身的对齐值:char型数据自身对齐1字节,short型数据为2字节,int/float型为4字节,double型为8字节。
2):结构体或类的自身对齐值:其成员中自身对齐值最大的那个值。
3):指定对齐值:#pragma pack(value)时的指定对齐值value。
4):数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐者中较小者,即有效对齐值=min{自身对齐值,当前指定的pack值}。
2.结构体的成员变量要对齐存放,结构体本身也要根据自身的有效对齐值圆整(即结构体成员变量占用总长度为结构体有效对齐值得整数倍)。
结构体字节对齐的细节和具体编译器实现相关,一般满足3准则:
1):结构体变量的首地址能够被其最宽基本类型成员的大小所整除。
2):结构体每个成员相对结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3):结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后填充字节{trailing padding}。
案例:
typedef struct test { int b; char a; double c; }; typedef struct test1 { int b; double c; char a; }; typedef struct test2 { char a; struct test3 //提供一个结构体类型;若提供实体,则程序运行结果为32 { char a1; int b1; double c1; }; double c; }; int main() { test T1; cout<<sizeof(T1)<<endl; test1 T2; cout<<sizeof(T2)<<endl; test2 T3; cout<<sizeof(T3)<<endl; return 0; }
位域对齐
定义:位域是一种特殊的结构成员和联合成员(即只能用在结构和联合中),用于指定该成员在内存存储时所占用的位数。
位域定义形式:
struct 位域结构名
{ 位域列表 };
位域列表定义形式:
类型说明符 位域名:位域长度;
位域的使用形式:
位域变量名.位域名;
对齐准则:
1):如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2):如果相邻位域字段的类型相同,但其位宽之和大小类型的sizeof带下,则后面的字段将重新在新的存储空间开始,其偏移量为其类型大小的整数倍;
3):如果相邻的位域字段的类型不同,则各编译器的具体实现有差异VC6采取不压缩,
Dev-C++和GCC采取压缩方式;
4):如果位域字段之间穿插着非位域字段,则不进行压缩;
5):整个结构的总大小为最宽基本类型成员大小的整数倍,而位域则按照其最宽类型字节数对齐。
案例:
struct StructBitField{ int a1 : 1; int a2 : 5; int a3 : 29; int a4 : 6; char a5 :2; char a6; //在含位域的结构或联合中也可同时说明普通成员 }; void main() { StructBitField t; cout<<sizeof(t)<<endl; }