结构体是一种自定义数据的类型。 当我们需要描述一个学生的时候,我们不能用一个int类型或者是char类型来描述一个学生,这时候就需要用结构体来描述。
结构体的使用
//定义一个学生类型的结构体
struct Student
{
int id;
char name[20];
char sex[3];
}s1, *s2;
//最后的分号要记得
//可以直接在结构体类型后面定义结构体变量和结构体指针,s1就是变量,s2是指针
int main()
{
//定义一个学生
struct Student s;
s.id = 100;
s.name = "susan";
s.sex = "nv";
return 0;
}
typedef struct Student
{
int id;
char name[20];
char sex[3];
}stu;
//这里是给struct Student类型取了一个别名,可以用stu定义结构体变量
int main()
{
//定义一个学生
stu s;
s.id = 100;
s.name = "susan";
s.sex = "nv";
return 0;
}
结构体内存对齐
为什么要内存对齐
struct A
{
int a;
char b;
int c;
double d;
};
如果没有内存对齐,那么处理器访问c和d的时候都要访问两次才可以拿到完整数据
总的来说,需要内存对齐的原因有两点
1.平台原因,不是所有的硬件平台都能在任意位置访问数据的;有的硬件平台只能在特定位置处取出特定数据
2.性能原因,数据结构(尤其是栈)应该尽可能的在自然边界对齐。 访问内存不对齐的数据处理器可能要访问两次内存,内存对齐的数据处理器只需要访问一次即可
总结:结构体的内存对齐是拿空间换时间的做法
怎么样进行内存对齐
内存对齐的规则大概可以分为两个步骤
1.让结构体中的变量对齐; 结构体中的第一个变量是不用对齐的,对于剩下的变量来说,对齐数 = min(变量大小,默认对齐参数),如果当前位置不在对齐数的整数倍,就进行补位,然后把变量放到对齐数的整数倍上
2.让结构体对齐,先看算下来的整个结构体的变量是不是在对齐数上,对齐数 = min(最大变量大小,默认对齐参数),结构体的最终大小一定是对齐数的整数倍
vs的默认对齐数是8
现在我们来计算一下下列结构体的大小
struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));
1.先对齐结构体中的变量:c1占用了一个字节,对于i来说,对齐数 = min(4, 8) ,所以我们要对齐到4的整数倍上,进行补位,补3个字节放i,对于c2来说,对齐数 = min(1, 8), 不用进行补位,因为任何数都是1的整数倍
2.再对齐整个结构体:现在S1共占用9个字节,对齐数 = min(4, 8) ,因为9不是4的整数倍,所以我们要补齐到12个字节
所以sizeof(struct S1)的答案是12
struct S2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S2));
1.先对齐结构体中的变量:c1占用了一个字节,对于c2来说,对齐数 = min(1, 8), 不用进行补位,因为任何数都是1的整数倍,对于i来说,对齐数 = min(4, 8) ,所以我们要对齐到4的整数倍上,进行补位,补2个字节放i,
2.再对齐整个结构体:现在S2共占用8个字节,对齐数 = min(4, 8) ,因为8是4的整数倍,所以我们不需要补齐字节
所以sizeof(struct S2)的答案是8
由此我们可以得出一个结论,在一个结构体中,优先把所有字节小的变量放在前面,可以节省空间
struct S3
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S3)); //8
//练习4-结构体嵌套问题
struct S4
{
char c1;
struct S3 s3;
double d;
};
printf("%d\n", sizeof(struct S4));
1.先对齐结构体中的变量:c1占用了一个字节,对于s3来说,对齐数 = min(8, 8), 所以我们要对齐到8的整数倍上,补7个字节放s3,对于d来说,对齐数 = min(8, 8) ,刚好是对齐数的整数倍,不需要对齐
2.再对齐整个结构体:现在S4共占用24个字节,对齐数 = min(8, 8) ,因为24是8的整数倍,所以我们不需要补齐字节
所以sizeof(struct S2)的答案是8
总结:如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
如何设置默认对其参数
pragma预处理指令
#include <stdio.h>
#pragma pack(4) //设置默认对齐参数为4
struct S3
{
double d;
char c;
int i;
};
#pragma pack() //取消设置默认对齐参数
怎么实现offsetof
求结构体中某个成员相当对于结构体起始位置的偏移量?
#include <stdio.h>
struct S3
{
double d;
char c;
int i;
};
int main()
{
//打印c对于结构体起始位置的偏移量
printf("%d\n", offsetof(struct S3, c)); //8
return 0;
}
让我们来看一下offsetof的原型
offsetof(s, m) (size_t)&(((s*)0)->m);
其中,s指的是 结构体类型,m指的是变量
C++和C语言中struct的区别:
-
C中定义的时候需要在前面加上struct,而C++中不用
-
C++把struct当成类处理,C++的struct中可以自己设定访问权限,而C中没有访问权限
-
C++中struct可以有成员函数,而C中不能有成员函数
-
C++中struct可以继承,而C中不能继承