共用体,也称联合(Union),是将不同类型的数据组织在一起共同占用同一段内存的一种构造数据类型。共用体与结构体的类型声明方法类似,只是关键字变为了Union。
例题:演示共用体所占内存字节数的计算方法
#include <stdio.h>
union sample
{
short i;
char ch;
float f;
};
struct ampl
{
short i;
char ch;
float f;
};
typedef union sample SAMPLE;
int main(void)
{
printf("bytes = %d\n",sizeof(SAMPLE));
printf("bytes = %d\n",sizeof(ampl));
return 0;
}
为什么共用体类型和结构体类型占用的内存字节数会如此不同呢?
这是因为,虽然共用体与结构体都是不同类型的数据组织在一起,但与结构体不同的是,共用体是从同一起始地址开始存放成员的值,即共用体中不同类型的成员共用同一段内存单元,因此必须由足够大的内存空间来存储占据内存空间最多的那个成员,所以共用体类型所占的内存空间的大小取决于其成员中内存空间最多的那个成员变量。
C语言规定,共用体采用与开始地址对齐的方式分配内存空间。本例中的共用体成员i占2个字节,ch占1个字节,f占4个字节 ,于是f的前1个字节就是为ch分配的内存空间,而前2两个字节就是为i分配的内存空间。共用体使用覆盖技术来实现内存共享,即当对成员f进行赋值操作时,成员i的内容将改变,于是i就失去了其自身的意义,再对ch进行赋值操作时,f的内容又被改变,于是f又失去了其自身的意义。由于同一内存单元再每一瞬时只能存放其中一种类型的成员,也就是说同一时刻只有一个成员是有意义的。因此,在每一瞬时起作用的成员就是最后一次被赋值的成员。
正因如此,不能为共用体的所有成员同时进行初始化,C89规定只能对共用体的第一个成员进行初始化,但C99没有这个限制,允许按名设置成员的初值。
此外,共用体不能进行比较操作,也不能作为函数参数…………………………
采用共用体存储程序中逻辑相关但情形互斥的变量,使其共享内存空间的好处是除了可以节省内存空间以外,还可以避免因操作失误引起逻辑上的冲突。例如,在职工数据库库管理中涉及某个人的婚姻状况时,一般有三种可能:未婚,已婚,离婚。任何一个人在同一时间只能处于其中的一种状态。
struct date
{
int year;
int month;
int day;
};
struct marriedstate
{
struct date marryDay;
char spouseName[20];
int child;
};
struct divorceState
{
struct date divorceDay;
int child;
};
union maritalState
{
int single;
struct marriedState married;
struct divorceState divorce;
};
struct person
{
char name[20];
char sex;
int age;
union maritalState marital;
int marryFlag;
};
第18~23行定义了一个表示婚姻状况的共用体类型union maritalState,它的3个成员分别表示未婚、已婚、离婚三种婚姻状况。其第2个成员married使用第7~12行定义的已婚结构体类型struct marriedState 来定义(如第21行所示),第3个成员divorce使用第13~17行定义的离婚结构体类型struct divorceState来定义(如第22行所示)。
第24~31行定义了一个代表职工个人信息的结构体类型struct person,其第4个成员是一个表示婚姻状况的共用体变量,使用第18~23行定义的union maritalState 共用体类型来定义。person-》marryFalg是用来标志婚姻状况的,因为表示婚姻状况的共用体变量有三个,如果不设定标志我们无法得知是使用的哪个。
1--未婚;2--已婚;3--离婚
例题:简易的显示婚姻状况
int main(void)
{
date birthday ={1991,10,10};
marriedState married = {{2010,10,30},"吴",2};
maritalState marry = {0};
person id = {"赵",'F',35};
maritalState marital={0};
id.marryFlag = 2;
// printf("%d/%d/%d",birthday.year,birthday.month,birthday.day);
printf("%s%4c%4d",id.name,id.sex,id.age);
if(id.marryFlag==2)
{
printf("\n");
printf("//----------------------婚姻状况-----------------------//\n");
printf("结婚日期:");
printf("%4d%4d%4d",married.marryDay.year,married.marryDay.month,married.marryDay.day);
printf("\t");
printf("配偶姓名:");
printf("%2s",married.spouseName);
printf("\t");
printf("子女数量:");
printf("%d\t",married.child);
}
}