前言
无论你是学C还是C++,求结构体的大小是很热门的考点,所以我们先思考这样一个问题:计算结构体,联合体和类的大小应该怎么去计算呢?我们知道,在C语言中结构体内部可以包含很多变量,所以我们在没有学习这个知识之前,会固化地认为,结构体的大小就是内部变量的大小的总和,但是事实就是这样吗?显然并不是,那接下来我们就要去学习一下如何求结构体它们的大小!
一、内存对齐规则(每一个都是重点)
1. 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
(只有VS中默认对齐数值为8,其他编辑器(gcc,clang)的对齐数就是成员自身的大小)
2. 结构体中第一个成员
永远在与 结构体变量地址的偏移量为0 的地址处。
(类似于数组第一个元素的地址,就是在整个数组的地址偏移量为0的地方)
3. 其他成员变量
对齐到 自身对齐数的整数倍 的地址处,之后占的空间是自身字节大小。
4. 结构体总大小
计算完的大小再扩大到 最大对齐数(每个成员变量都有一个对齐数)的整数倍。
5. 一个结构体的成员有另一个结构体类型的变量
这个结构体类型的变量要对齐到自己的最大对齐数的整数倍处,然后占自身大小的字节数。
6. 结构体里有数组
我们数组的对齐数是数组元素类型的对齐数,之后在占整个数组大小的空间。
7. 设置默认对齐数
#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
二、求结构体大小的例题 (按编辑器没有默认对齐数)
例题1
#include <stdio.h>
struct S1
{
char c1;
int i;
char c2;
};
int main()
{
printf("%lu",sizeof(struct S1));
return 0;
}
答案及解析 12
例题2
#include <stdio.h>
struct S2
{
char c1;
char c2;
int i;
};
int main()
{
printf("%lu\n", sizeof(struct S2));
return 0;
}
答案及解析 8
例题3
#include <stdio.h>
struct S3
{
double d;
char c;
int i;
};
int main()
{
printf("%lu\n", sizeof(struct S3));
return 0;
}
答案及解析 16
例题4 (嵌套结构体)
#include <stdio.h>
struct S3
{
double d;
char c;
int i;
};
struct S4
{
char c1;
struct S3 s3;
double d;
};
int main()
{
printf("%lu\n", sizeof(struct S4));
return 0;
}
答案及解析 32
例题5(结构体内部有数组)
#include <stdio.h>
struct S1
{
char c1;
int arr[6];
};
int main()
{
printf("%lu",sizeof(struct S1));
return 0;
}
答案及解析 28
三、联合体的计算规则
联合体是共用同一块空间的
1. 联合的大小至少是最大成员的大小
2. 当联合体大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
3. 数组的对齐数是数组的一个元素的大小,再占整个数组大小的空间。
四、求union联合体大小的例题
例题1
#include <stdio.h>
union Un1
{
char c[5];
int i;
};
int main()
{
printf("%lu\n", sizeof(union Un1));
return 0;
}
答案及解析 8
例题2
#include <stdio.h>
union Un2
{
short c[7];
int i;
};
int main()
{
printf("%lu\n", sizeof(union Un2));
return 0;
}
答案及解析 16
五、求类大小
向结构体看齐,一样的规则哦!但是有几点不跟结构体一样;
1. 类的内部有成员变量和成员函数,我们只算成员变量的就行,不需要算成员函数;
2. 不包含成员变量的类默认的大小是1字节,空类也是1字节
3. 静态成员变量不属于实例化对象,所以不会占类的空间,因为静态成员变量是一种特殊的静态全局变量,写在类里是为了表明它在哪个作用域而已。
4. 类里面包含类,计算大小的时候,不需要算类里面的类,内部的类其是跟我们外部的类平行的关系,放在类里面只是为了在访问的时候,需要指明在哪个作用域里。
例题1
#include <iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
};
int main()
{
cout << sizeof(A) << endl;
return 0;
}
答案及解析 1
没有成员变量的类大小为1个字节;
例题2
#include <iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
double _a;
char _b;
int _c;
};
int main()
{
cout << sizeof(A) << endl;
return 0;
}
答案及解析 16
算类的大小,只需要算成员变量的大小,不需要算成员函数,因为成员函数属于类的共有部分,每个实例化对象都有这个函数,难道我们每次实例化一次对象,就要创造成员函数吗?很显然不是,因为太消耗空间里,而每个实例化对象都必须有属于自己的成员变量,这是毋庸置疑的;
例题3 (静态成员变量)
#include <iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
double _a;
static int _b;
};
int main()
{
cout << sizeof(A) << endl;
return 0;
}
答案及解析 8
静态成员变量是所有类的实例化对象共享的,并不是每个对象都要创建的,所以跟成员函数一个道理,不用算
例题4 (类类型的成员变量)
#include <iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
double _a;
};
class B
{
private:
int _b;
A _a;
};
int main()
{
cout << sizeof(B) << endl;
return 0;
}
答案及解析 16
要注意的是这不是内部类,是在成员变量里有一个A类类型的变量,这就跟结构体里面有另外一个结构体变量一样,如果一个结构体的成员有另一个结构体类型的变量,这个结构体类型的变量要对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数的整数倍。
例题5 (内部类)
#include <iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
double _a;
class B
{
private:
int _b;
};
};
答案及解析 8
内部类不需要算,因为是与外部类平行的关系