共用体:
union //联合--共用体
在C语言中,共用体(Union)是一种特殊的数据类型,它允许不同类型的数据共享同一块内存空间,其主要特点和相关概念如下:
定义与语法
共用体使用union关键字来定义,语法形式为:
union 共用体名 {
数据类型1 成员名1;
数据类型2 成员名2;
// 可以有多个不同类型的成员
数据类型n 成员名n;
};
例如:
union Data {
int i;
float f;
char c;
};
内存占用
共用体的大小取决于其最大成员的大小。在上述union Data的例子中,如果int类型占4个字节,float类型也占4个字节,char类型占1个字节,那么union Data占用的内存空间为4个字节,因为它要保证能容纳下最大的成员int或float。
成员访问
共用体可以通过成员名来访问其成员,但在某一时刻只能有一个成员的值是有效的。比如:
union Data data;
data.i = 10;
// 此时data.i的值是有效的,data.f和data.c的值是不确定的
data.f = 3.14;
// 此时data.f的值是有效的,data.i和data.c的值被覆盖
使用场景
• 节省内存:当程序需要处理不同类型的数据,但这些数据不会同时使用时,使用共用体可以节省内存空间。
• 数据解析:在网络通信或文件格式解析中,可能会接收到不同类型的数据,但它们在内存中的存储格式是特定的,这时可以使用共用体来方便地解析数据。
⭐️与结构体的区别
结构体的所有成员都有自己独立的内存空间,整个结构体的大小是所有成员大小之和(考虑内存对齐)。而共用体的所有成员共享同一块内存空间,大小取决于最大成员。
早期的时候,计算机的硬件资源有限,
能不能让多个成员变量 公用同一块空间
//使用方式 类似 结构体 --- 也是构造类型
struct 结构体名
{
成员变量名
};
union 共用体名
{
成员变量名
}; //表示构造了一个共用体类型
//定义变量
//定义指针
//定义数组
//做函数形参
//做函数返回值类型
注意:
1.共用体类型的大小 = 最大的成员的大小
2.共用体初始化,只能写一个值,这个值是给第一个成员变量的值
3.共用体成员的访问方式 和 结构体一样
4.共用体因为公用同一块空间
赋值时,后赋值的会影响前面赋值的结果
5.用途
a.节省空间
校园人员管理系统
struct student
{
char name[20];
int sno;
float score;
};
struct teacher
{
char name[20];
int tno;
float salary;
};
struct member
{
char name[20];
int no;
union
{
float salary;
float score;
}data;
};
struct member s;
printf("score = %f\n",s.data.score);
struct member t;
printf("score = %f\n",s.data.salary);
b.数据转换
192.168.0.59 //ip地址 --- 网络环境中 ---实际对应是一个32位的数值
#include <stdio.h>
union Ip
{
unsigned char ip[4];
unsigned int iip;
};
int main(int argc, const char *argv[])
{
union Ip d = {192,168,0,59};
printf("ip = %#x\n",d.iip);
return 0;
}
枚举:
在C语言中,枚举(Enumeration)是一种用户自定义的数据类型,用于将一组相关的常量用符号名称来表示,方便程序的编写和维护。以下是关于枚举的主要概念:
定义与语法
枚举使用enum关键字来定义,基本语法形式为:
enum 枚举名 {
枚举常量1,
枚举常量2,
// 可以有多个枚举常量
枚举常量n
};
例如,定义一个表示星期的枚举类型:
enum Weekday {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
};
枚举常量的值
默认情况下,枚举常量会自动被赋予从0开始的整数值,如上述MONDAY的值为0,TUESDAY的值为1,以此类推。也可以手动指定枚举常量的值,例如:
enum Weekday {
MONDAY = 1,
TUESDAY = 2,
// 其他常量按顺序依次递增
SUNDAY = 7
};
枚举变量的定义和使用
可以像使用其他基本数据类型一样定义枚举变量,例如:
enum Weekday today;
today = MONDAY;
然后可以在程序中根据枚举变量的值进行相应的操作,比如:
if (today == MONDAY) {
// 执行周一的相关操作
}
使用场景
• 提高代码可读性:用有意义的枚举常量名代替数字常量,使代码更易理解,如用MONDAY代替0来表示星期一。
• 限定取值范围:在函数参数或变量定义中使用枚举类型,可以限定其取值只能是枚举中定义的常量,有助于进行数据检查和错误处理。
• 状态标识:用于表示程序中的各种状态,如表示文件操作的状态,可以定义一个枚举来表示打开成功、打开失败、读取成功等状态。
练习:
学会从键盘输入 1到7 打印对应的星期 (英文)
如果一个变量只有几种可能的值,则可以定义为枚举类型。
所谓"枚举"是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
枚举 --- 提高代码可读性
魔数
幻数
枚举 --- 将变量的可能值(常量值) 一一列举出来
将有关联的常量值,一一列举出来,组合成一个枚举类型
enum 枚举名
{
枚举值
//sun,mon,tue,wed,thu,fri,sat
};
//构造了一个枚举类型
注意:
1.枚举类型 本质是 用int型数据表示的
枚举类型 设计的不严谨的地方
练习:
歌曲的状态
PLAYING 1
PAUSE 2
STOP 3
typedef //type define
表示给已有类型起别名
struct stu
{
};
struct stu s;
union demo
{
};
union demo d;
typedef struct stu s; //s是struct stu 这个类型的别名
s s1; //定义了一个 struct stu的变量
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
void (*signal(int signum, void (*handler)(int) ))(int) ;
typedef int array_t[4]; //一维数组
array_t b[3]; //array_t => int[4]
位运算:
指的是二进制位上的运算
用途:
嵌入式 --- 位运算 非常普遍
操作硬件
c语言位运算:
& 与
| 或
^ 异或
~ 取反
<< 左移
>> 右移
& 与
运算规则: 一假则假
| 或
运算规则: 一真则真
^ 异或
运算规则: 相同为0 不同为1
<< 左移 a<<n
运算规则: 将 左操作数a 左移 n位
左移一位 相当于 结果乘以2
int a = 0x55;
a & 0x33
0101 0101 //0x55
&0011 0011 //0x33
0001 0001 //0x11
0101 0101 //0x55
| 0011 0011 //0x33
0111 0111 //0x77
0101 0101 //0x55
^ 0011 0011 //0x33
0110 0110 //0x66
~ 0101 0101 //0x55
1010 1010 //0Xaa
嵌入式:
unsigned char reg = 0xff;
7654|3210
与 清0
或 置1
7654|3210
1111 1111
& 0
reg & 0xfe
int a;
将a中的所有偶数位 清0
int a = 0x1;
7654|3210
0000 0001 //1
0000 0010 //2
0000 0100 //4
0000 1000 //8
将a中的第5位 清0
~(1<<5)
0010 0000
1101 1111 & a
~(1<<5|1<<8|1<<11)
练习:
int a = 0xffffffff;
将a中的所有偶数位 清0
练习:
int a = 0;
将a中的所有奇数位 置1
1010
7654|3210
0000 0001 //1
0000 0010 //2
0000 0100 //4
0000 1000 //8
1000 0000
1100 0000 0
右移:
要看 要移动的数据的类型
看是有符号 --- 最高位补符号位 //算术右移
无符号 --- 最高位补0 //逻辑右移
练习:
考题: 计算 一个int 类型中有多少个1
int a = 12134;
1100 0001
& 1
0000 0001
【练习】
编写程序实现循环左移
i<<2;
1000 0000
step1:从最高位移出一位
是0还是1
step2:将最高位的 这个 0 或者 1
塞到尾部
step3:左移几位
循环走几遍
1101 1111 1111 1111 1111 1111 1111 1111
d
1011 1111 1111 1111 1111 1111 1111 1111
b