以下内容是在做牛客网的选择题遇到的困惑和总结,其中主要是引用的别人的博客或者答案,和加入了自己的一些总结,方便以后翻过来看时更加有条理。
一、理论说明
一个结构体变量定义完之后,其在内存中的存储并不等于其所包含元素的宽度之和。
1.有两个原则:
原则一:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为0计算)。
原则二:在经过第一原则分析后,检查计算出(最后所需)的存储单元是否为所有元素中最宽的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。
2.包含指针的情况:
只要记住指针本身所占的存储空间是4个字节就行了,而不必看它是指向什么类型的指针。
3.有关 #pragma pack(n)
参考:http://blog.csdn.net/mylinx/article/details/7007309
4.有关union:
取决于它所有成员中,占用空间最大的成员的大小,并且需要内存对齐
二、一些例子
1.
struct X
{
char a;
int b;
double c;
} S1;
分析:a:1, b:4,c:8 1+(3)+4+8=16
struct X
{
char a;
double b;
int c;
} S2;
分析: 1+(7)+8+4+(4:补充到最宽元素长度的倍数)=24
struct X
{
double a;
char b;
int c;
}S3;
分析:8+1+(3)+4=16
struct X
{
double a;
char b;
int c;
char d;
} S4;
8+1+(3)+4+1+()=24
2.
已知int占量字节,char占1个字节,float占4个字节,求sizeof(xc)
struct stu
{
union{
char bj[5];
int bn[2];
}class;
char xm[8];
float cj;
}xc;
注意 bj[5]是储存了5个char类型的数组,不要认为是指针,还有联合体选择最大的那个
5*1+(3)+8+4=20
3.
#pragma pack(2)
class BU
{
int number;
union UBffer
{
char buffer[13];
int number;
}ubuf;
void foo(){}
typedef char*(*f)(void*);
enum {hdd,ssd,blueray}sk;
}bu;
union 取决于它所有的成员中,占用空间最大的成员大小,并且需要内存对齐。
又因为有#pragma pack(2),对齐的字节数为2,union的大小为14,
void foo()不占字节
typedef char*(*f) (void*);不占
enum {hdd, ssd, blueray}disk;4个字节
故总共有22个字节。
4. void Func( char str[100]){} 中 sizeof(str)是多少?
数组作为参数时,[]中的数不起作用,传递的是首元素的地址,故为4个字节
5.在x86系统下,sizeof如下结构体的值是多少?
struct{
char a[10];
int b;
short c[3];
}
答案为24,char a[10]并不代表结构体需要对齐的长度为10,它只是10个char聚在一起,本质没有变化,所以对齐长度是10,
故 4(char a[4])+4(char a[4])+4(char a[2],内存对齐)+4(int)+4(short[2])+4(short[1],内存对齐)
6.
typedef struct list_t{
struct list_t *next;
struct list_t *prev;
char data[0];
}list_t;
sizeof(list_t)是8byte
柔性数组(参考http://blog.csdn.net/yby4769250/article/details/7294696):直观上来看就是0长数组
StructPacket
{
Int state;
Int len;
CharcData[0]; //这里的0长结构体就为变长结构体提供了非常好的支持
};
用途:长度为0的数组主要是为了满足需要变长度的结构体
用法:在一个结构体的最后,申明一个长度为0的数组,就可以使得这个结构体是可变长度的,对于编译器而言,该长度为0的数组并不占用空间,因为数组名本身不占用空间。
三、参考资料:
结构在内存中的对齐规则: http://blog.csdn.net/liukun321/article/details/6974282