在C语言中结构体运用的十分广泛,然而结构体的大小并不是简单的把结构体里面各个成员的大小进行相加,而是应该考虑到地址对齐对结构体大小的影响。
结构体的对齐方式确实很浪费空间,可是按照计算机的访问机制,这种对齐方式大大提升了计算机的访问效率。
结构体大小的计算方法:
从结构体的第一个成员向下开始计算,并遵循以下原则
①前面所有成员所占地址空间的大小必须是其后一个成员占地址空间大小的整数倍。(0是任何数的整数倍,或第一个成员除外)
②结构体的大小必须是结构体里面各个成员(数组除外;结构中包含结构体,且被包含的结构体只声明,没有定义结构体变量除外;结构体中包含联合体,且联合体只声明,没有定义联合体变量除外)大小的整数倍。
在Ubuntu中char占1个字节,short占2个字节,int占4个字节,float占4个字节,double占8个字节。
以下举例了几种结构体:
1、普通结构体
#include <stdio.h>
struct t
{
char a;//char占1个字节
char b;//char占1个字节,因为前面成员所占空间刚好是
//此成员大小的整数倍所以第一个成员和第二个成
//员之间不需要补位(地址偏移)
int i;//int占4个字节,因为前面成员总共占了2个字节,
//所以第二个成员和第三个成员之间需要补2个字节
};//所以该结构体的大小为1+1+2(补)+4=8个字节
int main()
{
printf("%ld\n",sizeof(struct t));
}
struct t
{
char a;//char占1个字节
int i;//int占4个字节,因为前面成员总共占了1个字节,
//所以第一个成员和第二个成员之间需要补3个字节
char b;//char占1个字节,因为前面成员总共占8个字节,
//是1个字节的整数倍
};//理论上该结构体的大小应该是1+3(补)+4+1=9个字节,但是不
//难发现9个字节并不是结构体各个成员的整数倍,所以还应该在第
//三个成员的后面补3个字节,即该结构体的大小为1+3(补)+4
//+1+3(补)=12个字节
2、结构体成员包含数组的结构体
struct t
{
char a;//占1个字节
char c[5];//可看成5个char占5个字节
int b;//占4个字节,因为前面所有成员占6个字节,不是4
//个字节的整数倍,所以在第二个成员和第三个成员
//之间要补2个字节
}//所以该结构体的大小为1+5+2(补)+4=12个字节
//注:在前文结构体大小的计算方法中,第二点括号有提到数组除
//外,原因就在这里,数组应拆开来看,不能看做一个整体哦,如
//果看成一个整体12个字节并不是5个字节的整数倍噢
3、成员包含结构体的结构体
truct t
{
char a;
struct s
{
int c;
char d;
};//此处结构体只声明,没有定义结构体变量,所以该声明
//的结构体在地址空间中并不占位置,在前文结构体大小
//的计算方法中,第二点括号有提到,原因就在此
int f;
double b;
};//该结构体的大小为1+3(补)+4+8=16个字节
struct t
{
char a;
struct s
{
int c;
char d;
}g;//此处定义并申明了结构体变量,在这里不用把结构体
//看成一个整体,应单独看成int和char类型的变量,
//不过需要注意的是结构体的前一个成员以及结构体内
//最后一个成员所占地址位数需满足该结构体中最大成
//员的大小(结构体最大成员比结构体前一个成员大时),
//即a后面需要补3个字节,d后面也需要补三个字节
char f;
int b;
};//所以该结构体的大小为1+3(补)+4+1+3(补)+4+4=20个字节
大家可以体会一下以下的例子
#include <stdio.h>
struct t
{
char a;
struct s
{
char c;
int d;
double h;
}g;
char f;
int b;
};
int main()
{
struct t z;
printf("%p\n",&z.a);
printf("%p\n",&z.g.c);
printf("%p\n",&z.g.d);
printf("%p\n",&z.g.h);
printf("%p\n",&z.f);
printf("%p\n",&z.b);
printf("%ld\n",sizeof(struct t));
}
#include <stdio.h>
struct t
{
double a;
struct s
{
int c;
char i;
}g;
char f;
int b;
};
int main()
{
struct t z;
printf("%p\n",&z.a);
printf("%p\n",&z.g.c);
printf("%p\n",&z.g.i);
printf("%p\n",&z.f);
printf("%p\n",&z.b);
printf("%ld\n",sizeof(struct t));
}
4、成员包含联合体的结构体
struct t
{
char a;
union s
{
int c;
char d;
double h;
}g;//联合体的大小等同于联合体里面最大成员的大小,与
//前文所说的结构体一样,如果只声明联合体,没定义
//联合体变量,则联合体就当成不存在
int f;
double b;
};//所以该结构体的大小为1+7(补)+8+4+4(补)+8=32个字节
5、指定对齐值的结构体
说明:#pragma pack(n)中的n可取1、2、4、8、16
如果成员的大小超过了pack的要求,就按照pack来对齐(并不遵循前面所述的计算方法);如果最大成员大小没有超过pack要求的大小,结构体大小的计算就用前面所提到的方法。
注:当成员的大小超过了pack的要求时,结构体的大小必须是n的整数倍。
#pragma pack(2)
struct t
{
char a;
int b;
double c;
};//所以该结构体的大小为1+1(补)+4+8=14个字节,这里并不需要
//满足结构体的大小必须是结构体里面各个成员大小的整数倍
#pragma pack(4)
struct t
{
char a;
int i;
char b;
};//所以该结构体的大小为1+3(补)+4+1+3(补)=12个字节,这里
//相当于可以把指定的对齐语句省略
#pragma pack(2)
struct t
{
char a;
int i;
char b;
};//所以该结构体的大小为1+1(补)+4+1+1(补)=8个字节
以上只是我的个人拙见,希望可以帮到大家,可能存在着很多错误的观点,希望有大神可以指出,此文也仅供大家参考。