1 共用体的概念
有时需要使几种不同类型的变量存放到同一段内存单元中。例如,可把一个整型变量、一个字符型变量、一个实型变量放在同一个地址开始的内存单元中(见图11.24)。以上3个变量在内存中占的字节数不同,但都从同一地址开始(图中设地址为1000)存放。也就是使用覆盖技术,几个变量互相覆盖。这种使几个不同的变量共占同一段内存的结构,称为共用体”类型的结构。
定义共用体类型变量的一般形式为
union }共用体名
{成员表列
}变量表列;
例如:
union data
{int i;
char ch;
float f;}
a,b,c:
也可以将类型声明与变量定义分开:
union data
{int i;
char ch;
float f;
};
union data a,b.c;
即先声明一个union data类型,再将a、b、c定义为 union data类型。当然也可以直接定义共用体变量,如:
Union
{int i;
char ch;
float f;
}a,b,c;
可以看到,“共用体”与“结构体”的定义形式相似。但它们的含义是不同的。
结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。
共用体变量所占的内存长度等于最长的成员的长度。例如,上面定义的“共用体”变量 a、b、c各占4个字节(因为一个实型变量占4个字节),而不是各占2+1+4=7个字节。
国内有些C语言的书把union直译为“联合”。作者认为,译为“共用体”更能反映这种结构的特点,即几个变量共用一个内存区。而“联合”这一名词,在一般意义上容易被理解为“将两个或若干个变量联结在一起”,难以表达这种结构的特点。日本就是用“共用体”这一术语的。但是读者应当知道“共用体”在一些书中也被称为“联合”。在阅读其他书籍时如遇“联合”一词,应理解为“共用体”。
2 共用体变量的引用方式
只有先定义了共用体变量才能引用它。而且不能引用共用体变量,而只能引用共用体变量中的成员。例如,前面定义了a、b、c为共用体变量,下面的引用方式是正确的:
a.i (引用共用体变量中的整型变量i)
a.ch (引用共用体变量中的字符变量ch)
a.f (引用共用体变量中的实型变量f)
不能只引用共用体变量,例如:
printf(" %d" ,a)
是错误的,a的存储区有好几种类型,分别占不同长度的存储区,仅写共用体变量名a:难以使系统确定究竟输出的是哪一个成员的值。应该写成printf(" %d" ,a. i)或print("%c",a.ch)等。
3 共用体类型数据的特点
在使用共用体类型数据时要注意以下一些特点:
(1)同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一种,而不是同时存放几种。也就是说,每一瞬时只有一个成员起作用,其他的成员不起作用,即不是同时都存在和起作用。
(2)共用体变量中起作用的成员是最后一次存放的成员,在存人一个新的成员后原有的成员就失去作用。如有以下赋值语句:
a.i=1;
a.c='a';
a.f=1.5;
在完成以上3个赋值运算以后,只有a.f是有效的,a.i和a.c已经无意义了。此时用 prntf(" %d",a.i)是不行的,而用printf("%f",a.f)是可以的,因为最后一次的赋值是向.I赋值。因此在引用共用体变量时应十分注意当前存放在共用体变量中的究竟是哪个成员。
(3)共用体变量的地址和它的各成员的地址都是同一地址。例如:&a.&a.i,&a.c、 la.都是同一地址值,其原因是显然的。
(4)不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,又不能在定义共用体变量时对它初始化。例如,下面这些都是不对的:
union
{int i;
char ch;
float f;
)a={1,'a',1.5); (不能初始化)
②=1; (不能对共用体变量赋值)
③m=a; (不能引用共用体变量名以得到一个值)
(5)不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针(与结构体变量这种用法相仿)。
(6)共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。
例11.12 设有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。可以看出,学生和教师所包含的数据是不同的。现要求把它们放在同一表格中,见图11.25。如果“job”项为”s”(学生),则第5项为class(班)。即Li是501班的。如果“job”项是“t”(教师),则第5项为position(职务)。Wang是prof(教授)。显然对第5项可以用共用体来处理(将calss和position 放在同一段内存中)。
num | name | sex | job | class(班) Position(职务) |
101 | Li | f | s | 501 |
102 | Wang | m | t | prof |
图11.25
要求输入人员的数据,然后再输出。可以写出下面的算法(见图11.26)。按此写出程序。为简化起见,只设两个人(一个学生、一个教师)。
struct
{int num;
char name[10];
char sex;
Union
{int class;
char position[10];
}category;
}person[2];
main()
{int n,i;
for(i=0;i<2;i++)
{scanf("%d %s %c %c" , &person[i]. num,person[i].name, & person[i].sex,&person[i].job);
If{person[i].job= ='s') scanf("%d",& person[i]. category.class);
else if ( person[i].job=='t') scanf("%s" , person[i]. category.position) ;
else printf("input error!");
}
printf("\n");
printf("No. Name sex job class/position\n");
for(i=0;i<2;i++)
{if(person[i].job=='s')
printf("%-6d %-10s %-3c %-3c %-6d\n",person[i]. num,person[i].name, person[i].
sex,person[i].job,person[i],category.class);
else
printf("%-6d %-10s %-3e %-3e %-6s\n", person[i]. num,person[i]. name, person[i].
sex, person[i].job,person[i],category, position);
运行情况如下:
101 Lils 501↙
102 Wang m t professor↙
No. Name sex job class/position
101 Li f s 501
102 Wang m t professor
可以看到:在main函数之前定义了外部的结构体数组person,在结构体类型声明中包括了共用体类型,category(分类)是结构体中一个成员名,在这个共用体中成员为calss和position,前者为整型,后者为字符数组(存放“职务”的值一字符串)。