✨✨ 欢迎大家来到贝蒂大讲堂✨✨
养成好习惯,先赞后看哦~
所属专栏:C语言学习
贝蒂的主页:Betty‘s blog
联合体又叫共用体,它是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。给联合体其中⼀个成员赋值,其他成员的值也跟着变化。
联合体的结构类似于结构体,由关键字union和多个成员变量组成。格式如下:
union [union tag]
{
member definition;
member definition;
…
member definition;
} [one or more union variables];
union data
{
int n;
char ch;
};
联合体也是可以嵌套使用的。
union Un1
{
char c[5];
int i;
};
union Un2{
int n;
union Un1 u1;
};
匿名联合体是一种特殊联合体,省略了联合体名称,这种联合体只能在其定义的代码块内使用一次。例如,如果你在一个函数内部定义了一个匿名联合体,则该联合体只能在该函数内部使用。当代码块执行完毕后,该联合体将不再可见。
union
{
int n;
char ch;
};
我们也可以使用typedef简化联合体。
typedef union Un1
{
char c[5];
int i;
}Un1;//之后可以使用Un1代替union Un1
联合体变量创建除了在创建联合体时候定义,也可以在主函数内定义并且同时能够对齐初始化。
用例如下:
union Un
{
char c;
int i;
};
int main()
{
//联合体的初始化
union Un u1 = { 'a',0 };//错误
union Un u2 = { 0 };//正确
return 0;
}
为了访问联合体的成员,我们使用成员访问运算符(.)。成员访问运算符是联合体变量名称和我们要访问的共用体成员之间的一个句号。下面是一个实例:
#include
typedef union Un1
{
char c[10];
int i;
}Un1;
int main()
{
Un1 u = { 0 };
printf("%d ", u.i);
printf("%s ", strcpy(u.c, "abcdef"));
return 0;
}
输出结果:
联合体的大小是其成员变量大小之和,还是和结构体一样遵循某种特殊规律呢?我们通过以下代码实验一下。
union Un
{
char c[5];
int i;
};
int main()
{
union Un u2 = { 0 };
printf("大小为%zd", sizeof(union Un));
return 0;
}
输出结果:
通过验证我们知晓联合体的大小并不是其成员变量大小之和,也是遵循某种特定的规律。
那么这种规律到底是什么呢?其实很简单
- 联合的⼤⼩⾄少是最⼤成员的⼤⼩。
- 当最⼤成员⼤⼩不是最⼤对⻬数的整数倍的时候,就要对⻬到最⼤对⻬数的整数倍。
- 对⻬数=编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。(VS 中默认的值为 8 ,Linux中gcc没有默认对齐数,对⻬数就是成员⾃⾝的⼤⼩)
知道了联合体的大小,我们也就会很容易知道它的内存存储方式了。下面有具体四个样例:
#include
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;
}
输出结果:
#include
//联合类型的声明
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;
}
输出结果:
示意图:
#include
union Un1
{
char c;
int i;
};
int main()
{
// 下⾯输出的结果是什么?
printf("大小为%d\n", sizeof(union Un1));
return 0;
}
输出结果:
示意图:
解析:
#include
union Un2
{
short c[7];
int i;
};
int main()
{
// 下⾯输出的结果是什么?
printf("大小为%d\n", sizeof(union Un2));
return 0;
}
输出结果:
示意图:
解析:
我们早在学习数据在内存中如何存储时就已经了解过一种判断大小端的方法,今天就为大家介绍另一种方法——通过联合体判断大小端,
还是这幅图,我们要判断大小端就需要判断第一位存储到底是01还是00。
那如何取出第一位呢?除了通过指针,我们也能利用联合体共用同一块内存这一性质判断。
代码如下:
int check_sys()
{
union
{
int i;
char c;
}un;
un.i = 1;
return un.c; //返回1是⼩端,返回0是⼤端
}
int main()
{
int ret = check_sys();
if (ret == 1)
{
printf("⼩端\n");
}
else
{
printf("⼤端\n");
}
return 0;
}
通过联合体我们可以节省一部分内存。比如:我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。
其他信息:
图书:书名、作者、⻚数
杯⼦:设计
衬衫:设计、可选颜⾊、可选尺⼨
我第一想法是通过一个结构体定义:
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; //尺⼨
};
上述的结构其实设计的很简单,⽤起来也⽅便,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的⼤⼩就会偏⼤,⽐较浪费内存。但是对于礼品兑换单中的商品来说,只有部分属性信息是常⽤的。⽐如:商品是图书,就不需要design、colors、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;
};
在 C 语言中,枚举(enum)是一种用户定义的数据类型,用于定义一个由标识符列表组成的整数常量集合。枚举类型通过关键字 enum来定义。
在实际应用中我们经常把能够且便于一一列举的类型用枚举来表示。就比如:一周的星期、一年的月份……,其基本语法如下:
enum 枚举类型名
{
标识符1,
标识符2,
…
};
接下来我们举个例子,比如:一星期有 7 天,如果不用枚举,我们需要使用 #define 来为每个整数定义一个别名:
#define MON 1
#define TUE 2
#define WED 3
#define THU 4
#define FRI 5
#define SAT 6
#define SUN 7
这个看起来代码量就比较多,接下来我们看看使用枚举的方式:
enum DAY
{
MON=1, //指定从1开始,否则默认从0开始
TUE,
WED,
THU,
FRI,
SAT,
SUN
};
和匿名结构体与匿名联合体类似,枚举也有匿名类型。
enum
{
APPLE,
BANANA,
ORANGE
};
我们也可以使用typedef简化枚举。
typedef enum DAY
{
MON = 1, //指定从1开始,否则默认从0开始
TUE,
WED,
THU,
FRI,
SAT,
SUN
}DAY;
typedef enum DAY
{
MON,
TUE,
WED,
THU,
FRI,
SAT,
SUN
}DAY;
int main()
{
for (int i = MON; i < SUN; i++)
{
printf("%d ", i);
}
return 0;
}
输出结果:
我们可以利用定义的枚举常量对枚举变量进行赋值。
typedef enum DAY
{
MON,
TUE,
WED,
THU,
FRI,
SAT,
SUN
}DAY;
int main()
{
DAY a = MON;//最好用枚举常量赋值
return 0;
}
枚举常量的大小同 int 的大小一样,都是四个字节。
我们可以通过以下代码来实验:
#include
enum color1
{
RED,
GREEN,
BLUE
};
enum color2
{
GRAY = 0x112233445566,
YELLOW,
PURPLE
};
int main()
{
printf("enum color1: %d\n", sizeof(enum color1));
printf("enum color2: %d\n", sizeof(enum color2));
return 0;
}
输出结果:
乍一看,我们可能会感觉枚举有点画蛇添足的感觉,那使用枚举到底有哪些优点呢?
优点:
- 增加代码的可读性和可维护性
- 和#define定义的标识符⽐较枚举有类型检查,更加严谨。
- 便于调试,预处理阶段会删除 #define 定义的符号
- 使⽤⽅便,⼀次可以定义多个常量
- 枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使⽤
枚举的使用常与switch语句联系起来。
#include
int main()
{
enum color { red = 1, green, blue };
enum color favorite_color;
/* 用户输入数字来选择颜色 */
printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): \n");
scanf("%d", &favorite_color);
/* 输出结果 */
switch (favorite_color)
{
case red:
printf("你喜欢的颜色是红色\n");
break;
case green:
printf("你喜欢的颜色是绿色\n");
break;
case blue:
printf("你喜欢的颜色是蓝色\n");
break;
default:
printf("你没有选择你喜欢的颜色\n");
}
return 0;
}