对齐方式确实很浪费空间,可是按照计算机的访问规则,这种对齐方式提升了效率。
#include<stdio.h>
#include<stdlib.h>
struct s1{
char ch1; //1
char ch2; //1
int i; //4 2
};
int main()
{
printf("char = %d\n",sizeof(char));
printf("float = %d\n",sizeof(float));
printf("int = %d\n",sizeof(int));
printf("double = %d\n",sizeof(double));
printf("S1 = %d\n",sizeof(struct s1));
return 0;
}
首先,第一个成员ch1 的偏移量为0(可以这么理解 距离结构体头距离为0),ch1的类型为char,大小为1字节,0被认为是任何数的整数倍,所以到ch1这里大小为1;
第二个成员ch2,ch2的偏移量是前面成员的大小和(这个大小和是遵循第一法则的前提下的大小和,不是随意加起来就行的),所以ch2的偏移量为1,1满足ch2的大小1的整数倍,所以到ch2这里大小为1+1 = 2;
最后i,int i的偏移量为1+1 = 2,但2不是int型大小4的整数倍,所以要在前面加上2(多偏移两个),将之变为4,才满足第一法则。
综上s1的大小为1+1+2+4 = 8;
struct s2{
char ch1; //1
int i; //4 3
char ch2; //1 3
};
根据第一法则可以简单计算下s2的大小:
到ch1这里为1
到int这里为1+3+4 = 8
到ch2这里 8+1 = 9;
但是运行结果为12。
因为9不是4和1的整数倍(遵循第二法则),所以要继续偏移,直到12。
struct s3{
char ch1;
int i;
char str[10];
};
1+3+4+10 = 18,因为18不是4的倍数,所以要偏移到20。这里偏移到20不是因为str数组的大小为10才偏移的,是因为i的大小为4,法则一和法则二都是除数组外。
当结构体里有数组的时候,数组那一成员不遵循偏移量和数组成员大小对齐法则,直接将前面的大小加上数组的大小。 举个例子:
struct demo{
char ch1;
int i;
char str[32];
};
这个demo计算到int i的时候为8,8直接加上数组大小32为40,40正好是4的整数倍,所以demo的大小就为40。
再举个例子:
struct demo{
char ch1;
int i;
char str[55];
};
8+55 = 63,63不是4的整数倍,所以要偏移到64,即demo的大小为64。
struct s4{
char ch; //1
int i; //4 3
struct s{ //只是定义了个结构体 不算入
char ch1; //
int j; //
};
float f; //4
};
大小:12
struct s4{
char ch; //1
int i; //4 3
struct s{ //定义 并且占用内存8
char ch1; //1
int j; //4 3
}stmp;
float f; //4
};
里面这个结构体的大小是8,那么是否结构体大小就要向8对齐呢?这个结构体的大小是20,很明显不是8的倍数。所以计算结构体大小时是把里面这个结构体就看做是一个char,和一个int,不是看做一个整体。
struct s4{
char ch; //1
int i; //4 3
struct s{ //定义 并且占用内存
char ch1; //1
int j; //4 3
double d; //8
}stmp;
float f; //4
};
28(不是double的倍数+4)–>32
struct s5{
char ch;
int i;
union{
char ch1;
int j;
};
};
结果为12,算结构体大小的时候,如果里面有联合体,取联合体里面最大的成员计算。
#pragma pack(4) //指定向4对齐
struct s6{
char ch;
int i;
float f;
double d;
};
#pragma pack(4) 这句话是指定计算大小的时候向4对齐
结果为20,不加这句话结果就是24。
#pragma pack(10) //指定向10对齐
struct s7{
char ch;
int i;
float f;
double d;
};
1+3+4+4+4+8 = 24。
这一个在ubuntu中运行结果为24,没有对齐10,是因为最大时double,如果指定的比成员最大的还要大就按照成员最大的对齐。