首页 > 其他分享 >C语言自定义类型变量——联合体(union)

C语言自定义类型变量——联合体(union)

时间:2024-04-06 12:59:14浏览次数:15  
标签:perdata 变量 自定义 union 联合体 C语言 char int

前言:在之前的文章中我们介绍了C语言中自定义类型变量之一的结构体,本篇我们将介绍它的兄弟姐妹之一的联合体类型,何为联合体?如何声明?有什么特点?让我们一起揭开它神秘的面纱

 

一.何为联合体 ?

1.1联合体

我们知道,创建变量的过程本质上是在内存中为变量开辟一片内存空间的过程,每个变量都对应着相应的内存空间,各居其所,那么你是否试想过,多个不同变量是否能在同一块内存空间中先后存储呢?答案:yes。 

这便需要引入我们今天介绍的联合体。像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以是不同类型。但不同的是,编译器只为联合体最大的成员分配足够的内存中间。联合体的特点是所有成员共用同一块内存空间。因此,联合体又称为共用体。关键字union。

定义一个联合体的基本形式如下:

union 联合体名

{

        //成员变量;
};

1.2联合体类型的声明和定义

同结构体类似,联合体也与结构体具有类似的声明和定义方式,具体如下:

//一.同时创建模板和变量
union perdata
{
	char c;
	int i;
}un;

//二.先定义模板,再定义变量
union perdata
{
	char c;
	int i;
};

union perdata un1, un2;

//三.匿名联合体(一次性的,后面不能再次使用它定义新变量)
union
{
	char c;
	int i;
}un1, un2;

//使用typedef
typedef union perdata
{
	char c;
	int i;
}U_data;

U_data un1, un2;

1.3联合体的初始化

联合体初始化也类似于结构体,大致有以下三种方式:

一.将一个联合体初始化为另一个同类型联合;

二.一般初始化方式(仅初始化联合体第一个变量);

三.根据C99标准指定初始化方式。

union perdata
{
	int num;
	char name;
}a,b;

int main()
{
	//一.将一个联合体初始化为另一个同类型联合
	a.num = 10;
	union perdata b = a;
	printf("%d\n", b.num);
	//二.一般初始化方式(仅初始化联合体第一个变量)
	union perdata b = { 10 };
	printf("%d\n", b.num);
	//三.指定初始化方式
	union perdata b = {.num=10};
	printf("%d\n", b.num);
    return 0;
}

 但是由于联合体自身特点,若是大家初始化的时候不小心,就会存在一下情况:

union perdata
{
	int num;
	char name;
}a,b;

int main()
{
	
	a.num = 10;
	a.name = 'c';
	union perdata b = a;
	printf("%d\n%c", b.num,b.name);//结果如何呢?
	return 0;
}

这个代码结果是否会如我们所想的10和c呢?

结果显示联合体b中的num并没有如我们所想的初始化为10,这是为什么呢?这便与联合体成员变量共用同一片内存空间的特点息息相关。

给联合体其中一个成员赋值,其他成员的值也跟着变化!

二.联合体的特点 

在介绍联合体特点之前,我们先计算以下这个联合体的大小:

 为什么是4呢?

2.1联合体的共用特性

联合的成员是共用同⼀块内存空间的,这样⼀个联合变量的大小,⾄少是最⼤成员的大小(因为联合至少得有能⼒保存最⼤的那个成员)。

如何证明联合体的成员是共用同一块内存空间的呢?

eg1:

union perdata
{
	char c;
	int i;
};

int main()
{
	union perdata un = { 0 };
	//下面输出结果是否一致?
	printf("%p\n", &(un.i));
	printf("%p\n", &(un.c));
	printf("%p\n", &un);
	return 0;
}

结果:

0000007A68F4F744
0000007A68F4F744
0000007A68F4F744 

说明联合体存储变量的时候都是从一个相同地址处开始存储的。

eg2:

union perdata
{
	char c;
	int i;
};

int main()
{
	union perdata un = { 0 };
	un.i = 0x11223344;
	un.c = 0x55;
	printf("%x\n", un.i);
	return 0;
}

结果:

11223355 

为什么会是11223355呢?这既与小端存储有关,也与联合体的共用特性有关。

 

 如图可以直观地观察到联合体中内存是如何存储以及修改变量的。这里也要注意,联合体覆盖变量时从低地址处开始覆盖。

 2.2联合体与结构体相同成员对比

 我们会有疑问,已经有了结构体变量,为什么还要引入联合体呢?正如一句话:存在即合理。联合体的出现必然是它存在一些异于结构体的优势,例如空间占用少。如图:

 2.3联合体大小计算

在了解了联合体的特点之后,我们来看看联合体大小是如何计算的,我们已经知道了联合体各个成员公用同一块内存空间并且⼀个联合变量的大小,⾄少是最⼤成员的大小,那么许多人单纯地将联合体大小认为是最大成员变量的大小。事实并非如此。

1.联合的⼤⼩⾄少是最⼤成员的⼤⼩。

2. 当最⼤成员⼤⼩不是最⼤对⻬数的整数倍的时候,就要对⻬到最⼤对⻬数的整数倍。

union Un
{
	char c[5];//1 8 1
	//5个char,char对齐数为1,整体对齐数只与变量类型有关而与个数无关 
	int i;//4 8 4
};

int main()
{
	printf("%zd\n", sizeof(union Un));//8
	return 0;
}

 最大成员变量大小为5,但根据最大对齐数4,联合体空间需对齐到最大对齐数整数倍,所以要对齐到8,即联合体大小为8。

还不了解对齐数相关问题同学请移步C语言自定义类型变量——结构体(一)

三.联合体的应用 

 联合体基本介绍已经结束,接下来我们探讨一下联合体的实际应用:

3.1应用1

我们知道联合体是可以节省空间的,举例:⽐如,我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。 每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。

假设我们没有学习过联合体,使用结构体将如何书写呢?

struct gift_list
{
	//公共属性 
	int stock_number;//库存量 
	double price; //定价 
	int item_type;//商品类型 

	//特殊属性 
	 char title[20];//书名 
	char author[20];//作者 
	int num_pages;//⻚数 
	char design[30];//设计 
	int colors;//颜⾊ 
	int sizes;//尺⼨ 
};

利用结构体这样设计其实很简单,用起来也不麻烦,但是结构体的每个成员变量都是单独开辟空间的,结构的设计包含了所有礼品的各种属性,会使得结构体大小偏大,十分浪费内存资源,这不是我们所希望的。因为对于礼品单中的商品来说,部分信息是常用的,比如就图书而言,描述它就不需要设计design,颜色colors,尺寸sizes。

所以我们就可以把公共属性单独写出来,剩余属于各种商品本⾝的属性使⽤联合体起来,这样就可以 介绍所需的内存空间,⼀定程度上节省了内存。

结构如下:

struct gift_list
{
	int stock_number;//库存量
	double price;//价格
	int item_type;//商品类型

	union
	{
		struct
		{
			char title[20];//书名
			char author[20];//作者
			int num_pages;//页数
		}book;
		struct
		{
			char design[30];//设计
		}mug;
		struct
		{
			char design[30];//设计
			int colors;//颜色
			int sizes//尺寸
		}shirt;
	}item;
};

3.2应用2

eg:写一个程序,判断当前机器的大小端?

int check_sys()
{
	union
	{
		int i;
		char c;
	}un;
	un.i = 1;
	return un.c;
}
int main()
{
	printf("%d\n", check_sys());
	//结果为1则为小端
	//结果为0则是大端
	return 0;
}

 可知本机器为小端存储。

 以上便是对C语言中联合体有关内容介绍,望屏幕前的你能有所收获。

 

标签:perdata,变量,自定义,union,联合体,C语言,char,int
From: https://blog.csdn.net/2301_80827065/article/details/137422355

相关文章

  • Vue.js自定义指令
    除了默认设置的核心指令(v-model和v-show),Vue也允许注册自定义指令。下面我们注册一个全局指令v-focus,该指令的功能是在页面加载时,元素获得焦点:<body><divclass="app"><span>页面载入时,input元素自动获取焦点:</span><inputv-focust......
  • 【C语言初阶】指针运算
    【C语言初阶】指针运算文章目录【C语言初阶】指针运算四、指针运算1介绍2指针+-整数2.1示例3指针-指针3.1示例3.2模拟实现`strlen()`3.2.1方法一:指针-指针3.2.2方法二:计数器3.2.3方法三:函数递归4指针的关系运算4.1示例14.2示例24.3标准规定总......
  • 【C语言初阶】指针
    【C语言初阶】指针文章目录【C语言初阶】指针一、指针是什么?1指针是什么?2内存2指针变量2.1示例2.2总结3如何编址?3.1编址3.1总结二、指针和指针类型1指针的类型1.1示例2指针+-整数2.1示例2.2总结3指针的解引用3.1示例3.2总结总结:本章目标:......
  • 中国电子学会(CEIT)2021年09月真题C语言软件编程等级考试三级(含详细解析答案)
    中国电子学会(CEIT)考评中心历届真题(含解析答案)C语言软件编程等级考试三级2021年09月编程题五道 总分:100分一、菲波那契数列(20分)菲波那契数列是指这样的数列:数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和。给出一个正整数a,要求菲波那契数列中第a......
  • 【华为OD机试真题】211、最优资源分配、芯片资源占用 | 机试真题+思路参考+代码分析(C
    文章目录一、题目......
  • C语言简易版杀戮尖塔
    此代码仅包含4种卡牌(可增加其它id的卡牌效果函数)此项目仅有一个固定攻击模式的boss。以下是实现代码,#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<time.h>intdeck[10]={1,1,1,1,2,2,2,2,3,4};inthand[5]={0};......
  • 【c语言】自定义类型:联合体(公用体)【详解】
    联合体联合体类型的声明像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫:共用体。给联合体其中⼀个成员赋值,其他成员的值也跟着变化。......
  • c语言之多重指针
    多重指针是定义了一个指针a后,又定义一个指针b引用指针a的地址,就叫多重指针多重指针定义的方法:类型名**指针名#include<stdio.h>intmain(){ inta; a=3; int*p=&a; int**y=&p; printf("%d\n",a); printf("%d\n",*p); printf("%d\n",**y); return0;}上面代码......
  • c语言之指针数组
    在c语言中,一个数组元素是由指针组成的,就叫指针数组。指针数组的定义方法类型名*数组名[数组长度]如果要处理多个字符串,用指针数组会方便多。举个例子,代码如下#include<stdio.h>intmain(){ inti; char*s[]={"cprogram","control","logic"}; for(i=0;i<3;i++) ......
  • 【C语言学习】之字符数组与字符串处理函数
    1.字符数组1.字符数组的初始化1.单字符形式chara[3]={'a','b','c'}                定义一个字符型一维数组,数组名a,三个下表变量a,b,ccharb[][3]={'a','b','c','d','e','f','g'}  ......