C语言之union共同体
文章链接
知识点
- union共同体的定义;
- union空间长度的分配;
- 共同体个变量相互影响及原因;
- union的使用样例;
- 新名词记录{union共同体;Unicode;}
概述
在C语言中,给我们提供了分配和操作一块内存的方式,那就是union关键字。union关键字,定义union下面的成员变量共享一块内存,每一个成员在任一时刻有且只有一个成员使用此块内存。
因为C语言只管分配一段空间,至于里面放什么内容,系统都不会管。结构体strcut也是如此。
定义
下面直接看如何定义union共同体。共同体是会按照成员中最大的一个数据长度分配空间。
union data{
int i;
double d;
char str[20];
};
解释:在上面的共同体中,定义了3个成员,i占用4个字节,d占用8个字节,而str则占用20个字节,所以data的空间长度是20个字节。
data共同体名字可以不写,而在最后面也可以加入union的名字,创建union的同时,创建union变量,这个写法和strcut是一样的。eg
union data{
int i;
double d;
char str[20];
}d1, d2;
d1.i = 11;
d2.i = 12;
因为有20个字节的空间,里面放入什么内容,取决于我们。例如下面的例子
union u uu;
uu.i = 10;
printf("%d\n",uu.i); //输出10
//下面根据每个字节放入字符
char * c;
c = (char *)&uu;//把union的首地址赋值、强转成char类型
c[0] = 'a';
c[1] = 'b';
c[2] = 'c';
c[3] = '\0';
c[4] = 'd';
c[5] = 'e';
//最多能到c[19]
printf("%s\n", c);//利用结束符'\0'打印字符串"abc"
printf("%c %c %c %c %c %c\n",c[0],c[1],c[2],c[3],c[4],c[5]);
//分别输出a, b, c, , d, e ,\0输出为空格
可以在上面看到,我们其实分别在第一个,第二个…等字节中存入了小写字符的值,然后输出每个字节,那么对应的就是每个代表的字符了。
union空间大小分配
那么union的分配是按照怎样的规则来分配的呢?
我们看下面的例子。
/**
* union分配空间大小说明
*/
void unionSizeTest()
{
union sizeTest{
int a;
double b;
};
union sizeTest unionA;
union sizeTest unionB;
union sizeTest unionC;
printf("the initial address of unionA is %p\n",&unionA);
printf("the initial address of unionB is %p\n",&unionB);
printf("the initial address of unionC is %p\n",&unionC);
//证明union分配的空间其实是连续分配的
/**
* the initial address of unionA is 0x7fff53801b08 140734594292488
the initial address of unionB is 0x7fff53801b00 140734594292480
the initial address of unionC is 0x7fff53801af8 140734594292472
*/
}
从打印的结果可以看出,a和b的地址差了0x08,而b和c之间也是差了0x8,可以看到相邻的两个union变量的空间长度都间隔8个字节。而这个字节则是double变量b的存储大小。因此,这里可以知道,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对应的字符了。那么导致的原因也就出来了。
共同体应用
(来自http://c.biancheng.net/cpp/html/2932.html)
一个实例是: 现有一张关于学生信息和教师信息的表格。学生信息包括姓名、编号、性别、职业、分数,教师的信息包括姓名、编号、性别、职业、教学科目。
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
*/
总结
上面讲到了union共同体的定义,如何分配空间,以及变量之间赋值错乱的导致原因。其实最主要的还是要理解union的空间分配以及基本数据类型占用的存储字节数。最后引用了一个union使用的例子,方便理解。
以上就是所有内容,如有任何问题,请及时与我联系。谢谢