目录
一、结构体类型的声明
-
结构的声明
注意:结构体类型的关键字是struct
struct Stu {
int a;
char b;
};
-
结构体变量的创建和初始化
//在声明结构体时创建变量
struct Str{
int a;
char b;
}s,str;//两个变量之间用,隔开
//先声明后创建
struct Str{
int a;
char b;
};
int main()
{
//按照结构体成员的顺序初始化
struct Str s={3,"c"};//初始化时用大括号括起来,各个变量之间用,隔开
//按照指定的顺序初始化
struct Str s={.b="c",.a=3};
return 0;
}
-
结构体的特殊声明
在声明结构的时候可以不完全声明
#include <stdio.h>
//匿名结构体类型
struct {
int a;
char b;
float c;
}x;
struct {
int a;
char b;
float c;
}str,*p;
int main()
{
return 0;
}
由上代码可见,对于没有标签的结构声明,这两个变量是同一种类型吗我们可以做一下调试,发现编译器会把上面两个声明当作完全不同的两个类型,如果没有对结构体类型重命名,基本上只能使用一次
二、结构体内存对齐
1.对齐规则
- 结构体的第一个成员对齐到结构体变量起始位置偏移量为0的地址处
- 其他成员要对齐对齐数的整数倍的地址处
- 对齐数=编译器的默认对齐数与该成员变量大小的较小值
注意:vs中默认对齐数为8,linux和gcc中没有默认对齐数,对齐数就是成员自身大小
- 结构体总大小为最大对齐数(所有结构体成员中的最大值)的整数倍
- 如果出现结构体嵌套的现象,嵌套的结构体对齐到自己成员中最大对齐数的整数倍
下面我们用几个例题来讲解一下:
结构体嵌套情况:
此时struct S中嵌套了struct D
2.修改默认对齐数
#pragma这个预处理指令,可以改变编译器的默认对齐数
#include <stdio.h>
#pragma pack(1)//设置默认对齐数为1
struct S {
int a;
float b;
char c;
}s;
#pragma pack()//预处理指令一般不建议写在函数内部,包括主函数,因为预处理指令是在编译阶段进行处理的,作用域常常是全局
int main()
{
printf("%zd\n", sizeof(s));
//取消设置的对齐数,还原为默认
printf("%zd\n", sizeof(s));
return 0;
}
易错点:我们看到当恢复为默认对齐数时,结构体大小任然是9,这是因为在我重新恢复默认对齐数的时候,系统已经给这个结构体分配好了内存空间,后面再还原的时候也不会再重新分配了内存空间了,所以结构体的内存大小不变。
3.结构体传参
小tips:结构体传参的时候要传结构体的地址
我们知道函数中临时变量的创建需要压栈,会浪费时间和空间,特别是当一个结构体过大时,所以我们推荐传址。
总结
结构体的内存对齐是一个非常热门的问题,结构体的定义和使用也是C语言中的重要内容