欢迎光临
我们一直在努力

C语言--联合体

联合体

  • 一、联合体的声明和定义
  • 二、联合体的特点
  • 三、联合体和结构体对比
  • 四、联合体大小的计算
  • 五、联合体的应用与练习

一、联合体的声明和定义

与结构体相似,联合体也是由一个或者多个成员构成,这些成员可以是不同类型。 在C语言中联合体的 联合体的声明与定义和结构体类似:

union 联合体名
{
成员列表
}

例如:

union un
{
char a;
int i;
};

联合体的定义: 方法一:先声明在定义变量:

union un
{
char a;
int i;
};
int main()
{
union un u;
}

方法二:在声明时就创建变量:

union un
{
char a;
int i;
}u;

方法三:省略联合体名

union
{
char a;
int i;
}a, b;

既然没有联合体名,那就只能用一次,不能再用该联合体创建新的变量

二、联合体的特点

我们在学习了联合体的声明和定义后,发现联合体与结构体好像差不多,没有啥区别,其实不然。 我们来看一个例子:

union un
{
char a;
int i;
};
int main()
{
union un u = { 0 };
printf("%zd", sizeof(u));
return 0;
}

结果:在这里插入图片描述

a是char类型,占一个字节; i是int类型,占四个字节; 那么最起码联合体u的总大小要有5个字节吧?

那么是怎么一回事呢?为什么是4呢?

对于联合体,编译器只为最大的成员类型分配足够的内存空间。 联合体的特点是所有成员变量共用同一块内存空间,所以联合体也叫共用体。 联合的成员是共⽤同⼀块内存空间的,这样⼀个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

union un
{
char a;
int i;
};
int main()
{
union un u = { 0 };
printf("%p\\n", &u);
printf("%p\\n", &(u.a));
printf("%p\\n", &(u.i));
return 0;
}

我们对整个联合体和它的成员变量的地址打印: 在这里插入图片描述 我们发现竟然所有成员变量的地址都是一样的,a是一个字节,i是四个字节,所以a与i共用了第一个字节。 在这里插入图片描述 那也就证明了联合体的所有成员变量共用同一块内存空间。 但是,因为所有成员共用同一块内存空间,所以这些成员变量就不能同时使用,否则就会冲突; 而且对其中一个成员变量改变就会对其他成员变量的值改变。

比如:

union un
{
char a;
int i;
};
int main()
{
union un u = { 0 };
u.i = 0x11223344;
u.a = 0x55;
printf("%x", u.i);
return 0;
}

先给 i 赋值0x11223344 然后通过给a赋值0x55 因为整数在内存中是以小端字节序存储的,所以改变了放在低地址的44,改为了55

通过调试内存窗口查看: 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

结果:

在这里插入图片描述

三、联合体和结构体对比

结构体与联合体都是C语言中的自定义类型,包含多个成员变量。 但是 结构体的成员变量之间是相互独立的,每个成员变量都有自己单独的内存空间; 联合体是所有成员变量共用一块内存空间。

结构体:

struct S
{
char a;
int i;
};

联合体:

union un
{
char a;
int i;
};

在这里插入图片描述

四、联合体大小的计算

在上面我们提到了一个这样的例子

union un
{
char a;
int i;
};
int main()
{
union un u = { 0 };
printf("%zd", sizeof(u));
return 0;
}

我们知道这个代码中的联合体和联合体中内存最大类型的int的内存空间大小一样大,那么难道所有的联合体的大小就是最大成员的大小吗? 回答是:当然不是

对于联合体的大小:

联合体的大小至少是最大成员的大小当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍

上面那个例子刚好 i 的类型是int, 对齐数是4,a的类型是char,对齐数是1,最大对齐数是4,刚好是最大对齐数的整数倍。

所以我们在做两个题目来计算一下: 一:

union Un1
{
char c[5];
int i;
};
int main()
{
union Un1 u = { 0 };
printf("%zd", sizeof(u));
return 0;
}

char[ 5 ]就相当于5个char类型的数据,对齐数还是char类型的大小:1,但是总共占5个字节; i 是int类型,占4个字节,对齐数是4; 共用同一块内存空间所以是5个字节; 由于最大对齐数是4,所以必须要对齐到最大对齐数的整数倍,比5大且最近的就是8了,所以联合体的大小是8个字节。 结果: 在这里插入图片描述

二:

union Un2
{
short c[7];
int i;
};
int main()
{
union Un2 u = { 0 };
printf("%zd", sizeof(u));
return 0;
}

short类型是2个字节; short c [ 7 ]相当于7个short类型的数据,对齐数还是short类型的大小:2,但是总共c占14个字节; i对齐数是4,占4个字节;所以最大对齐数是4; 共用一块内存空间,所以是14个字节; 由于14不是4的整数倍,所以要对齐到16个字节。 在这里插入图片描述

五、联合体的应用与练习

学习了联合体,那么联合体有什么用吗?

我们了解了联合体大小的计算方法后,与结构体相比,联合体是比较节省内存空间的,所以当我们需要用当多个成员变量并且这些变量不会同时使用时,我们就可以采用联合体来节省内存空间。

比如: 假设我们要卖三种物品:图书,衬衫和杯子; 这三种物品有共同的属性:

库存量 价格 商品类型

但同时,这三种物品也有只属于它们自己的特殊属性:

图书:书名,作者,页数 衬衫:尺寸,设计 杯子:形状,颜色

它们的特殊属性之间没有联系,不会同时使用。 比如是图书,就不需要尺寸,形状,设计等等。 所以我们就可以使用比结构体更加节省空间的联合体来声明和定义这些特殊属性。

struct project
{
int stock_number;//库存量
int price;//价格;
int type;//类型
union Item
{
struct Book//书的特殊属性
{
int name[6];//书名
char author[10];//作者
int pages;//页数;
}book;
struct Cup//杯子的特殊属性
{
int shape;//形状
int color;//yanse
}cup;
struct Shirt//衬衫的特殊属性
{
char design[30];//设计
int size;//尺寸
}shirt;
}item;
};

练习:写一个程序,通过联合体判断当前机器是大端字节序存储还是小端字节序存储

之前我们判断的方法是通过对一个int类型的数字int n = 1,对它的地址强制类型转换成(char*)&,然后解引用访问第一个字节,看结果是1,就是小小端,结果是0,就是大端。

#include <stdio.h>
int check_sys()
{
int n = 1;
return *(char*)&n;
}
int main()
{
int ret = check_sys();
if (ret == 1)
printf("小端\\n");
else
printf("大端\\n");
return 0;
}

具体可以参考之前对数据在内存中的存储的笔记: http://t.csdnimg.cn/jtTi4

学习了联合体我们知道,联合体中所有成员共用一块内存空间,所以对其中一个成员变量改变,其他的成员变量也会随之发生改变。 所以我们想可以写这样一个联合体:

union un
{
char a;
int i;
}u;

我们把1赋值给 i ; a与 i 共用第一个字节,所以如果 a 的值是1,就是小端,如果是0,就是大端。 在这里插入图片描述

#include <stdio.h>
int check_sys()
{
union un
{
char a;
int i;
}u;
u.i = 1;
return u.a;
}
int main()
{
int ret = check_sys();
if (ret == 1)
printf("小端\\n");
else
printf("大端\\n");
return 0;
}

结果: 在这里插入图片描述

结语:C语言联合体的讲解到这里就结束了,本文中有错误或者有待改进的地方万望大家批评和指导,感谢您的阅读,拜拜! 在这里插入图片描述

赞(0)
未经允许不得转载:171主机测评 » C语言--联合体
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址