浅谈自定义类型(结构体/位段/枚举/联合)

核心

  1. 结构体类型创建
  2. 结构体初始化
  3. 结构体内存对齐 (对齐数,最大对齐数)
  4. 位段,位段计算机大小
  5. 枚举(常量)
  6. 联合(共用体)

具体

  • 结构体 : 结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
//结构体的声明
struct Student{
	char name[20];
	int age;
	char sex[5];
};
//结构体变量的定义,并初始化(结构体变量只有一次整体赋值的机会,就是在定义的时候)
struct Student stu = {"老王",20,"男"};

//声明的时候定义结构体变量 stu
struct Student{
	char name[20];
	int age;
	char sex[5];
} stu;

//声明结构体的时候定义结构体变量并初始化
struct Student{
	char name[20];
	int age;
	char sex[10];
} stu = {"老王",18,"未知"};

//结构体的自引用
struct Student{
	char name[20];
	int age;
	char sex[5];
	struct Student* node;//指向这个类型变量的指针
};

//结构体嵌套并初始化
struct People{
	int age;
	int weight;
	char name[10];
}
struct Student{
	char name[20];
	int age;
	char sex[5];
	struct People peo;
} stu = {"老王",18,"女",{20,180,"老李"}};
  • 结构体的内存对齐规则 :
    • 第一个成员在与结构体变量偏移量为 0 的地址处
    • 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
      • 对齐数 = 编译器默认的一个对齐数 与 该成员大小较小值
      • VS中默认的值为8 : Linux中的没有默认值
    • 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
    • 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所 有最大对齐数(含嵌套结构体的对齐数)的整数倍
struct Student{
	char name[20];//在偏移量为 0 的地方,占 20 个字节
	int age;//自身对齐数为 4,在vs默认值为 8,所以对齐数是 4,偏移量在 4 的整数倍处,偏移量为 20,占4个字节
	char sex[5];//对齐数为 1,偏移量为 24,占 5 个字节
	//结构体的总大小是每个对齐数的最大值的整数倍,最大对齐数是 4,总大小是 32
};

//结构体的嵌套
struct People{
	int age;//偏移量为 0,占 4 个字节
	int weight;//对齐数为 4,偏移量为 4,占 4 个字节
	char name[10];//对齐数为 1,偏移量为 8,占 10 个字节
	//总大小为 最大对齐数 4 的整数倍,为 20
};
struct Student{
	char name[20];//偏移量为 0,占 20 个字节
	int age;//对齐数为 4,偏移量为 20,占 4 个字节
	char sex[5];//对齐数为 1,偏移量为 24,占 5 个字节
	struct People peo;//此结构体的最大对齐数为 4,偏移量为 28,占 20 个字节
	//结构体的总大小为最大对齐数 4 的整数倍,为 52
} ;

//可以用 #pragma pack() 修改默认对齐数
#pragma pack(2) //把默认对齐数修改为 2

struct People{
	int age;//偏移量为 0,占 4 个字节
	int weight;//对齐数为 2,偏移量为 4,占 4 个字节
	char name[10];//对齐数为 1,偏移量为 8,占 10 个字节
	//总大小为 最大对齐数 2 的整数倍,为 18
};

#pragma pack() //还原为默认
  • 结构体传参 : 由于参数需要压栈,会有时间和空间上的系统开销。当一个结构体过大时,参数压栈的开销比较大, 会导致性能的下降.
  • 所以, 在传参时, 最好传结构体的地址
  • 位段 : 位段和结构体类似
    • 位段的成员必须是 int、unsigned int 或signed int
    • 位段的成员名后边有一个冒号和一个数字
  • 位段的内存分配 :
    • 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
    • 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的
    • 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段
struct Student{
	int age: 3;
	int height: 3;
	char sex: 4;
}
  • 枚举 :
    • 优点 :
    1. 增加代码的可读性和可维护性
    2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
    3. 防止了命名污染(封装)
    4. 便于调试
    5. 使用方便,一次可以定义多个常量
enum A{
	RED,
	GREEN,
	YELLOW,
	WHITE
};
//RED GREEN 都是常量,在没有赋初始值的时候,从 0 开始,依次增加
//RED 0
//GREEN 1
//YELLOW 2

//赋初始值
enum A{
	RED,// 0
	GREEN = 4,//此时,GREEN 代表的常量是 4
	YELLOW,// 5
	WHITE// 6
};
//枚举变量
enum A clr = RED;
clr = 6;
  • 联合
    • 联合的所有成员,公用一块空间
union un{
	char a;
	int b;
};
  • 联合内存 :
    • 联合的大小至少是最大成员的大小
    • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
union un{
	char a[9];//最大成员 9 个字节,最大对齐数 4,联合的大小 12
	int b;
};
union un{
	char a[19];//最大成员 19 个字节,最大对齐数 4,联合的大小 20
	int b;
};

over

发布了60 篇原创文章 · 获赞 5 · 访问量 2644

猜你喜欢

转载自blog.csdn.net/qq_44905386/article/details/100049029