详细介绍自定义类型 :结构体 枚举 联合体
这里写目录标题
结构体
结构体类型声明
struct Stu //类型声明
{//下面为结构体的属性
char name[20];
int age;
char sex[t];
}p1;//分号不能丢 p1是变量名可以省略
//也可以这样命名
struct Stu p2;
特殊声明
struct
{
int a;
char b;
float c;
}x;//匿名声明
结构体的自引用
struct Node {
int data;
struct Node* next;
};
结构体的初始化
struct A
{
int c;
int d;
double e;
};
struct B
{
char q;
struct A a;//嵌套
short h;
};
int main()
{
struct B b = { "d",{11,22,33.3},4 };//初始化
printf("%1f\n", b.a.e);
return 0;
}
结构体的计算–内存对齐
struct S1 {
char c1; //1个字节
int i; //4个字节
char c2; //1个字节
};
printf("%d\n", sizeof(struct S1));
//但是该题的答案不是1+4+1而是12
此处就需要了解对齐规则
- 第一个成员在与结构体变量偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。(vs中默认值8 linux默认值4)
- 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所 有最大对齐数(含嵌套结构体的对齐数)的整数倍。
通过上图就可以看出结构体s1的大小
c1是char类型 从0开始 1字节对齐,i是int类型 4字节对齐 要往后数为4的倍数开始,c2同c1往后一个。但是总数要是最大对齐数的整数倍所以是12。
因此在设计结构体时 尽量将小的变量放到前面可以节省空间
struct S1 {
char c1; //1个字节
char c2; //1个字节
int i; //4个字节
};
printf("%d\n", sizeof(struct S1));
//该题的答案就是8
当然默认值也可以进行修改
#pragma 这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数。
#pragma pack(1)//设置默认对齐数为1
struct S2 {
char c1;
int i;
char c2; };
#pragma pack()//取消设置的默认对齐数,还原为默认
int main() {
printf("%d\n", sizeof(struct S2));
return 0;
}
//此时结果为6
结构体传参
struct S
{
int data[1000];
int num;
};
struct S s = { { 1, 2, 3, 4 }, 1000 };
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main() {
print1(s);//传结构体
print2(&s); //传地址
return 0; }
如同数组传参一样 传地址的方式更好 不需要压栈减小系统开销
位段
位段声明:(位段不能够跨平台)
1.位段的成员必须是 int、unsigned int 或signed int 。
2.位段的成员名后边有一个冒号和一个数字
int main()
{
struct A {
char _a : 2;
char _b : 5;
char _c : 4;
char _d : 8;
};
printf("%d\n", sizeof(struct A));
}
//该题的结果是3
- 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
- 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
位段相比较结构体 更节省空间
枚举
枚举类型的定义
enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex//性别
{
MALE,
FEMALE,
SECRET
};
枚举的默认值都是从0开始;每次递增1; 当然也可以进行赋初值
enum Color//颜色
{
RED=1,
GREEN=2,
BLUE=4
};
枚举的优点
- 增加代码的可读性和可维护性
- 和#define定义的标识符比较枚举有类型检查,更加严谨。
- 防止了命名污染(封装)
- 便于调试
- 使用方便,一次可以定义多个常
联合体
联合体的定义
//联合类型的声明
union Un
{
char c;
int i;
};
//联合变量的定义
union Un un;
//计算连个变量的大小
printf("%d\n", sizeof(un));
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有 能力保存最大的那个成员)。
联合体的计算
联合的大小至少是最大成员的大小。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
union Un1 {
char c[5];
int i; };
union Un2 {
short c[7];
int i; };
//下面输出的结果是什么?
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));
Un1中 c需要5个空间最大对齐1 i需要4个空间 最大对齐4 因此要大于5且是4的整数倍所以是8
Un2中c需要14个空间 最大对齐2 i需要4个空间最大对齐4 因此要大于14 且是4的整数倍所以是16