C++中的字节对齐

一、字节对齐的定义
计算机在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

二、对齐的作用和原因
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐。

2、性能原因:最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问,而对齐的内存访问仅需要一次访问。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。

三、字节对齐的规则

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数),一般来讲,在32位机器上,默认对齐数是4字节, 64位机器上默认对齐数是8字节. 我们可以通过预编译命令#pragma pack(n),n=1,2,4,8,16 来改变这一系数,其中的n就是你要指定的“对齐系数”。

注意,以下例子在64位OS下

规则一、 结构体中每个数据成员在结构体中的起始位置,应该是 MIN(这个数据成员的字节数, 对齐系数)。比如,下面的两个例子:

例一:

struct Exmp
{
    char a;
    int c;
    double b;
    
};

在例一中,cha a占一个字节,起始位置从0开始, int c 占4个字节,但它的起始位置不能从1,开始,而是从4开始,double  b 占8个字节,从位置8开始,这三个数据成员共占用4+4+8=16个字节

例二:

struct Exmp
{
    char a;
    double b;
    int c;
    
};
//sizeof (struct Exmp) = 8 + 8 + 4 + 4 = 24

在例二中, char a 占用一个字节,位置从0开始,double b占8个字节位置从8开始,位置1~7填充占位符,int c 从 16开始,占4字节,这里要注意,在确定完,各个数据成员的起始位置和所占字节后,整个结构体的大小,还应该做一些调整,以遵守如下规则:

规则二整个结构体的大小,应该是MIN(其最长数据成员所占字节, 对齐系数)的整数倍。 例二中,三个数据成员所占的字节是8 + 8 + 4 = 20, 20并不是最长数据成员(double b)所占字节数(8 byte)的整数倍,所以末尾再加四字节凑成24。

例三:

#pragma pack(2)
struct Exmp
{
    char a;
    double b;
    int c;
    
};
// sizeof(struct Exmp) = 2 + 8 + 4 = 14 

在例三中,指定了对齐系数是2, char a占一个字节,仍然从0开始,double 占8个字节,但起始位置从min (8,2)= 2位置开始,int c占4字节,起始位置从min(4,2)= 2的整数倍位置10开始,size = 2+8+4 = 14,在这种情况下,整个结构体的大小需要是(对齐系数=2,最大数据成员所占字节double b=8)= 2的整数倍

规则三:如果有嵌套结构体,那么内嵌结构体的第一个成员变量在外结构体中的偏移量,是“MIN(对齐字节,内嵌结构体中那个数据类型大小最大的成员变量)”的倍数。

例四:

struct TEST 
{
    int a;  
    char b; 
    char c; 
    int d;
    char e;
    struct child {
        int f;
        long long g;  //8 bytes
    }ch;
    char ci;
};
// sizeof(struct TEST)  = 40

例四中,int a 占4字节,char b,c占一字节,后面填充两个字节,int d起始位置8,占四个字节,char e,占一个字节,起始位置12, 结构体 child 中的一个数据成员的起始位置=MIN(最长数据成员所占字节 long long g =8, 对齐系数=8)= 8的整数倍,所以 char e 后填充3字节,int f从16开始,f后填充4字节,long long f 从24开始,char ci,占用1字节,填充7字节

总结:字节对齐,就是要解决两件事儿:

1. 当前数据成员从哪个偏移位置开始,这个起始位置取决于 MIN(这个数据成员的字节数, 对齐系数) 

2. 当前数据成员后需要填充多少字节,取决于下一个数据成员的起始位置。当 当前数据成员为结构体中最后一个数据成员时,则填充字节数取决于规则二

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值