共用体引入
共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。
学过结构体之后,共用体就比较简单,这么说吧,把结构体的struct换成union,其他的语法格式都是一样的。
//格式: union 共用体名 { 成员列表; }; //示例 union test { char c; short s; int i; } t1;//定义共用体类型的同时顶定义变量
既然有了结构体,那还要共同体干嘛呢?
共用体union和结构体struct在类型定义、变量定义、使用方法上很相似。
共用体和结构体的不同:结构体类似于一个包裹,结构体中的成员彼此是独立存在的,分布在内存的不同单元中,他们只是被打包成一个整体叫做结构体而已;共用体中的各个成员其实是一体的,彼此不独立,他们使用同一个内存单元。可以理解为:有时候是这个元素,有时候是那个元素。更准确的说法是同一个内存空间有多种解释方式,共用体union就是对同一块内存中存储的二进制的不同的理解方式。
在有些书中把union翻译成联合(联合体),这个名字不好。现在翻译成共用体比较合适。
union的sizeof测到的大小实际是union中各个元素里面占用内存最大的那个元素的大小。因为可以存的下这个就一定能够存的下其他的元素。共用体成员具有瞬时性
由于共用体成员之间共用一段内存,所以,共用体成员的赋值会相互影响,最后一次更新的值为有效值!如果定义了几个变量,但是在没有使用之前,就重新赋值,那么前后的值就会有覆盖。具体问题如下所示。
void unitTest(){ union Data{ int i; float f; char str[20]; }; union Data data; data.i = 10; printf("data.i=%d\n", data.i); data.f = 225.6; printf("data.f=%f\n",data.f); strcpy(data.str, "tanksu"); printf("data.str=%s\n", data.str); //如果直接全部赋值,那么里面的值就有损坏 //如下代码 /** * data.i = 10; data.f = 220.5; strcpy( data.str, "C Programming"); * * 输出: * data.i : 1917853763 data.f : 4122360580327794860452759994368.000000 data.str : C Programming */ }
上面的结果可以看出来:共用体成员之间会相互影响,修改一个成员的值会影响其他成员。
那么这是如何来影响的呢?
这个共同体需要的空间长度为20个字节,那么我们填充i,只需要填充前面4个字节,而填充f,则需要前面8个字节,但是如果我填充str,则取药填充20个字节。一句话来说,填充f,会影响i;填充str,则会影响i和f。那么就可以知道,在我们填充了C Programming字串之后,i只需要前4位的字节,f需要前8位的字节。那么取出来对应的Unicode码对应的字符应该就不是前面赋值给i和f对应的字符了。那么导致的原因也就出来了。
union中的元素不存在内存对齐的问题,因为union中实际只有1个内存空间,都是从同一个地址开始的(开始地址就是整个union占有的内存空间的首地址),所以不涉及内存对齐。
共用体和结构体的相同和不同
相同点就是操作语法几乎相同。
不同点是本质上的不同。struct是多个独立元素(内存空间)打包在一起;union是一个元素(内存空间)的多种不同解析方式。
应用
共用体的主要用途
共用体就用在那种对同一个内存单元进行多种不同规则解析的这种情况下。
C语言中其实是可以没有共用体的,用指针和强制类型转换可以替代共用体完成同样的功能,但是共用体的方式更简单、更便捷、更好理解。一个实例是: 现有一张关于学生信息和教师信息的表格。学生信息包括姓名、编号、性别、职业、分数,教师的信息包括姓名、编号、性别、职业、教学科目。
f 和 m 分别表示女性和男性,s 表示学生,t 表示教师。
如果把每个人的信息都看作一个结构体变量的话,那么教师和学生的前 4 个成员变量是一样的,第 5 个成员变量可能是 score 或者 course。当第 4 个成员变量的值是 s 的时候,第 5 个成员变量就是 score;当第 4 个成员变量的值是 t 的时候,第 5 个成员变量就是 course。
#include <stdio.h> #include <stdlib.h> #define TOTAL 4 //人员总数 struct{ char name[20]; int num; char sex; char profession; union{ float score; char course[20]; } sc; } bodys[TOTAL]; int main(){ int i; //输入人员信息 for(i=0; i<TOTAL; i++){ printf("Input info: "); scanf("%s %d %c %c", bodys[i].name, &(bodys[i].num), &(bodys[i].sex), &(bodys[i].profession)); if(bodys[i].profession == 's'){ //如果是学生 scanf("%f", &bodys[i].sc.score); }else{ //如果是老师 scanf("%s", bodys[i].sc.course); } fflush(stdin); } //输出人员信息 printf("\nName\t\tNum\tSex\tProfession\tScore / Course\n"); for(i=0; i<TOTAL; i++){ if(bodys[i].profession == 's'){ //如果是学生 printf("%s\t%d\t%c\t%c\t\t%f\n", bodys[i].name, bodys[i].num, bodys[i].sex, bodys[i].profession, bodys[i].sc.score); }else{ //如果是老师 printf("%s\t%d\t%c\t%c\t\t%s\n", bodys[i].name, bodys[i].num, bodys[i].sex, bodys[i].profession, bodys[i].sc.course); } } return 0; } /* 运行结果: Input info: HanXiaoXiao 501 f s 89.5↙ Input info: YanWeiMin 1011 m t math↙ Input info: LiuZhenTao 109 f t English↙ Input info: ZhaoFeiYan 982 m s 95.0↙ Name Num Sex Profession Score / Course HanXiaoXiao 501 f s 89.500000 YanWeiMin 1011 m t math LiuZhenTao 109 f t English ZhaoFeiYan 982 m s 95.000000 */