Linux环境下
一、不同数据类型所占用的内存大小
32位 64位
char 1 1
int 4 大多数4,少数8
short 2 2
long 4 8
float 4 4
double 8 8
指针 4 8
(单位都为字节)
结构体(struct):比较复杂,对齐问题。
联合(union):所有成员中最长的。
枚举(enum):根据数据类型。
二、sizeof计算单层结构体大小
运算符sizeof可以计算出给定类型的大小,例如:sizeof(char) = 1;
数组是相同类型的元素的集合,整个数组所占空间等于基础元素大小乘上元素的个数。
结构体中的成员可以是不同的数据类型,成员按照定义时的顺序依次存储在连续的内存空间。和数组不一样的是,结构体的大小不是所有成员大小简单的相加,需要考虑到系统在存储结构体变量时的地址对齐问题。
举个栗子:
struct stu1
{
int i;
char c;
int j;
};
用sizeof求该结构体的大小,发现值为12。int占4个字节,char占1个字节,结果应该是9个字节才对啊,在此之前先介绍一个相关的概念——偏移量。偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体大小等于最后一个成员的偏移量加上最后一个成员的大小。显然,结构体变量中第一个成员的地址就是结构体变量的首地址。因此,第一个成员i的偏移量为0。第二个成员c的偏移量是第一个成员的偏移量加上第一个成员的大小(0+4),其值为4;第三个成员j的偏移量是第二个成员的偏移量加上第二个成员的大小(4+1),其值为5。
然而,在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:
(1)结构体变量中成员的偏移量必须是成员自身大小的整数倍(0被认为是任何数的整数倍)
(2)结构体大小必须是所有成员的整数倍,也即所有成员大小的公倍数。(另一个名字叫 补齐)或者说最大成员
注意:在计算对齐和补齐时,LINUX中成员超过4字节按4字节计算,而WINDOWS系统按规定计算
上面的例子中前两个成员的偏移量都满足要求,但第三个成员的偏移量为5,并不是自身(int)大小的整数倍。编译器在处理时会在第二个成员后面补上3个空字节,使得第三个成员的偏移量变成8。结构体大小等于最后一个成员的偏移量加上其大小,上面的例子中计算出来的大小为12,满足要求。
不同的顺序会影响结构体的大小。
对比下面两种定义顺序:
struct stu3
{
char c1;
int i;
char c2;
}
struct stu4
{
char c1;
char c2;
int i;
}
虽然结构体stu3和stu4中成员都一样,但sizeof(struct stu3)的值为12,而sizeof(struct stu4)的值为8。
三、sizeof计算嵌套的结构体大小
对于嵌套的结构体,需要将其展开。对结构体求sizeof时,上述两种原则变为:
(1)展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大成员的整数倍。
(2)结构体大小必须是所有成员大小的整数倍,这里所有成员计算的是展开后的成员,而不是将嵌套的结构体当做一个整体。
struct stu5
{
short i;
struct
{
char c;
int j;
} ss;
int k;
}
结构体stu5的成员ss.c的偏移量应该是4,而不是2。整个结构体大小应该是16。
struct stu5
{
char i;
struct
{
char c;
int j;
} ss;
char a;
char b;
char d;
char e;
char f;
}
结构体ss单独计算占用空间为8,而stu5的sizeof则是20(1->4;4+1=5;5->8;8+4=12;12+5=17;17->20),不是8的整数倍,这说明在计算sizeof(stu5)时,将嵌套的结构体ss展开了,这样stu5中最大的成员为ss.j,占用4个字节,20为4的整数倍。
如果将ss当做一个整体,结果应该是24了。
struct ss
{
float f;
char p;
int adf[3];
};
结构体中包含数组,其sizeof应当和处理嵌套结构体一样,将其展开。其值为20。float占4个字节,到char p时偏移量为4,p占一个字节,到int adf[3]时偏移量为5,扩展为int的整数倍,而非int adf[3]的整数倍,这样偏移量变为8,而不是12。结果是8+12=20,是最大成员float或int的大小的整数倍。