struct大小、首地址与内存对齐

结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

编译器在给结构体开辟空间时,首先找到结构体中最宽的基本数据类型,然后寻找内存地址能被该基本数据类型所整除的位置,作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐模数。即每个结构体对象的第一个成员地址受结构体中最宽的成员数据类型影响。

结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);

为结构体的一个成员开辟空间之前,编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍,若是,则存放本成员,反之,则在本成员和上一个成员之间填充一定的字节,以达到整数倍的要求,也就是将预开辟空间的首地址后移几个字节。即结构体中每个程序的地址受自身数据类型影响,不受其它成员数据类型影响。如果结构体中前面成员所占用的字节宽度不是本成员的整数倍,会先填充空字节,确保符合此规则。

结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节(trailing padding)。

结构体总大小是包括填充字节,最后一个成员满足上面两条以外,还必须满足第三条,否则就必须在最后填充几个字节以达到本条要求。即最后一个成员后面可能会被自动填充空字节,确保整个结构体的字节宽度是最大成员数据类型宽度的整数倍。

强制内存对齐方式 #pragma pack

可以使用预处理指令#pragma pack修改默认的内容对齐方式,如下代码ITMSRC_STRING_TEST_MESS_PARAM_V1的长度为16,ITMSRC_STRING_TEST_MESS_PARAM_V2的长度为20。

//按4字节开始对齐
#pragma pack(4)

typedef struct
{
    ITMSRC_MESSAGE_VERSION  version;
    long long               ct_time;
    PPA_BOOL                loopback;
    char                    string[100];
}ITMSRC_STRING_TEST_MESS_PARAM_V1;

//恢复默认对齐方式
#pragma pack()
typedef struct
{
    ITMSRC_MESSAGE_VERSION  version;
    long long               ct_time_send;
    PPA_BOOL                loopback;
    char                    string[100];
}ITMSRC_STRING_TEST_MESS_PARAM_V2;

int i = sizeof(ITMSRC_STRING_TEST_MESS_PARAM_V1); //116
int j = sizeof(ITMSRC_STRING_TEST_MESS_PARAM_V2); //120
cout << i << endl << j << endl;