目录
1.联合体
1.1联合体的声明
联合体也是由一个或者多个成员构成,这些成员可以不同的类型。但是 编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共用同一块内存空间。所以联合体也叫:共用体。
给联合体其中一个成员赋值,其他成员的值也跟着变化
#include<stdio.h> union Un//联合体声明 { char c; int i; }; int main() { union Un un={0};//定义联合体变量 printf("%d\n",sizeof(un)); return 0; }
1.2联合体的特点
联合的成员是共用同一块内存空间的,这样一个联合体变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)
//代码1 #include <stdio.h> //联合类型的声明 union Un { char c; int i; }; int main() { //联合变量的定义 union Un un = {0}; // 下⾯输出的结果是⼀样的吗? printf("%p\n", &(un.i)); printf("%p\n", &(un.c)); printf("%p\n", &un); return 0; } //输出的结果是一样的,因为联合体的成员共用一个空间 那么不管是整个联合体的首地址,又或者是其中成员的首地址,就都是一样的了 //代码2 #include <stdio.h> 联合类型的声明 union Un { char c; int i; }; int main() { //联合变量的定义 union Un un = {0}; un.i = 0x11223344; un.c = 0x55; printf("%x\n", un.i); return 0; } 输出结果是11223355 因为int类型占4字节,联合体会申请4字节的空间,这空间是联合体成员共用的 而char类型占1字节,所以如果要共用的话,char类型会将int类型数据的低位字节替换掉
1.3相同成员的结构和联合体对比
struct S { char c; int i; }; struct S s = {0}; 首先c变量会从偏移量0开始,占一个字节 接着int类型又是4字节,然后vs默认字节数8,所以取4 偏移量1不是4的倍数,所以跳到偏移量4开始,占4个字节 union Un { char c; int i; }; union Un un = {0}; 由于最大的类型是int,所以联合体的空间申请的4个字节 而这4个字节中,int类型数据的高位3个字节占据4个字节中的3个字节, 剩下char类型再占据剩下的1个字节
1.4联合体大小的计算
联合的大小至少是最大成员的大小
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
#include <stdio.h> union Un1 { char c[5]; int i; }; union Un2 { short c[7]; int i; }; int main() { //下⾯输出的结果是什么? printf("%d\n", sizeof(union Un1)); printf("%d\n", sizeof(union Un2)); return 0; } //因为char类型本身只有1个字节,vs默认字节数是8,取1 但char类型数组,一共占了5个字节,然后int类型是4字节,但偏移量5不是4的倍数 所以int类型会从偏移量8开始,前面的空间会浪费掉,所以要申请8个字节 //第二个,因为是short类型,一共14个字节,然后int类型只占4字节, 但为了匹配整数倍,所以要申请16个字节
联合体可以节省空间:
我们要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有3种商品:图书、杯子、衬衫。
每种商品都有:库存量、价格、商品类型和商品类型相关的其他信息
图书:书名、作者、页数
杯子:设计
衬衫:设计、可选颜色、可选尺寸
简单粗暴的设计:
struct gift_list { //公共属性 int stock_number;//库存量 double price; //定价 int item_type;//商品类型 //特殊属性 char title[20];//书名 char author[20];//作者 int num_pages;//⻚数 char design[30];//设计 int colors;//颜⾊ int sizes;//尺⼨ }; //这样写虽然很万能,但是不同类型的商品,总有几个属性是不用的 这样就会浪费
因此可以使用联合体
struct gift_list { int stock_number;//库存量 double price; //定价 int item_type;//商品类型 union{ struct { char title[20];//书名 char author[20];//作者 int num_pages;//⻚数 }book; struct { char design[30];//设计 }mug; struct { char design[30];//设计 int colors;//颜⾊ int sizes;//尺⼨ }shirt; }item; }; //将公用的属性直接放入结构体,但特有的属性 通过联合体,在联合体内部创建3个不同商品特有属性的结构体 这样联合体运用时只会使用相应的商品属性
1.5练习
int check_sys() { union { int i; char c; }un; un.i = 1; return un.c; } //由于联合体中,小类型占据空间是从最大类型的低位地址开始占据, 因此un.c可以看到低位地址的内容 那么如果un.c的值是低位数据也就是1,那么就是小端,如果是0,那就是大端
2.枚举
2.1枚举类型的声明
枚举就是列举
把可能值一一列举
enum Day//星期 { Mon,//默认0 Tues,//递增1,所以是1 Wed, Thur, Fri, Sat, Sun }; enum Sex//性别 { MALE, FEMALE, SECRET }; enum Color//颜⾊ { RED, GREEN, BLUE }; {}中的内容是可能取值,也是枚举常量 这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值
2.2枚举类型的优点
枚举可以增加代码可读性和可维护性—可以将一些数字赋予常量,然后将常量直接拿来使用。这些枚举变量可以直接代表相应的枚举常量
和define相比,枚举有类型检查,更严谨
便于调试,预处理阶段会删除define定义的符号
可以一次性定义多个常量
枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用
2.3枚举使用
enum Color//颜⾊ { RED=1, GREEN=2, BLUE=4 }; enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值
在c语言中可以拿整数给枚举变量赋值,但C++不行,c++的检查类型比较严格。