在C语言编程中,有时为了达到减少运行的时间的目的,需要浪费一些空间;而有时为了节省空间,使它的运行时间增长。而字节对齐则是为了访问效率,用空间换取时间。
要掌握字节对齐,首先得明确一下四个概念:
1.基本数据类型的自身对齐值
在32位系统下基本数据类型有其自身的对齐值:
char 1个字节
short 2个字节
Int 4个字节
double 8个字节
2.程序指定的对齐值
用#pragma(value)显式指定对齐值value
3.自定义类型的自身对齐值
即结构体或类的成员自身对齐的最大值
4.自定义类型的有效对齐值
自定义类型的自身对齐值和指定对其中最小的值
#include<stdio.h>
typedef struct Test
{
char a;
double b;
int c;
}Test;
void main()
{
printf("sizeof(Test) = %d ",sizeof(Test));
}
对于Test结构体来说,首先先列出来结构体中数据成员数据类型的大小:
char a占4个字节,double b占8个字节,int c占4个字节。求出结构体的大小分两个步骤:
1.从结构体的第一个元素往下看,下面的数据的大小是上面数据大小的整数倍,如b的大小为8,而a的大小为4,a不为b的整数倍,所以给a补4个字节,使为b的整数倍。注意上面的概念为这个数据上面的所有类型大小之和。
2.看是否与自定义类型的对齐值对齐。上面已经解释过了自定义类型的对齐值即结构体或类的成员自身对齐的最大值,对于这个例子来说,double数据类型的大小为Test结构体中最大的,所以Test结构体的对齐值为8.所谓对齐,就是看所有数据大小之和是否是自定义类型的对齐值的整数倍。
从上面我们发现,当数据排放位置不同,结构体所占大小会有所变化,当自定义类型中的元素按类型的大小从小到大排列时,所占空间最小。
当结构体中嵌套结构体时不要慌,只要把构体看成一个数据元素,求解顺序跟上面的步骤是一样的。
当结构体按一个字节对齐时,结构体大小就是各成员自身大小之和。
当程序用#pragma(value)指定对齐值为value时,就要考虑有效的对齐值,如上所言:自定义类型的自身对齐值和指定对其中最小的值,这是什么意思呢?就拿上面的例子来说,如果指定对齐的value为4的话,自定义类型自身的对齐值为8,但是程序指定对齐值为4,所以他的有效对齐值为二者中最小的那个,即结构体的有效对齐值为4.针对这个例子,b占8个字节,a占一个字节,c占4个字节,所以给a补齐3个字节,所以结构体的总大小就是16个字节,是4的整数倍,不再需要补齐。因此最终结构体的大小就是16.
当内嵌结构体有名字时,结构体上升为类型,不占空间大小,而内嵌结构体有名字时,可以简单地看做其内部数据成员,不过要受到内嵌结构的约束,并且内嵌结构体自身也要对齐。