C语言:自定义类型:结构体,枚举,联合(2)


目录

2. 位段

2.1 什么是位段

2.2 位段的内存分配

2.3 位段的跨平台问题

3. 枚举

3.1 枚举类型的定义

3.2 枚举的优点

3.3 枚举的使用

4. 联合(共用体)

4.1 联合类型的定义

4.2 联合的特点

4.2.1 联合体的应用:判断大小端字节序存储模式

4.3 联合大小的计算


2. 位段

2.1 什么是位段

位段的声明和结构是类似的,有两个不同:

1.位段的成员必须是 int、unsigned int 或signed int 。

2.位段的成员名后边有一个冒号和一个数字。

//位段
#include<limits.h>
struct AA
{
	int _a;//INT_MIN  ~  INT_MAX
	int _b;
	int _c;
	int _d;
};

struct A
{
	int _a : 2;//_a这个成员只占两个bit位就可以了
	int _b : 5;//_b这个成员只占五个bit位
	int _c : 10;
	int _d : 30;
};

int main()
{
	printf("%d\n", sizeof(struct AA));//16个字节
	printf("%d\n", sizeof(struct A));//8个字节
	return 0;
}

根据场景,现实及需求,选择是否使用位段

2.2 位段的内存分配

  • 1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
  • 2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
  • 3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
//位段在内存中的使用
struct A
{
	int _a : 2;//首先分配4个字节,_a用了2个bit位	30	
	int _b : 5;//_b再次使用了5个bit位				25
	int _c : 10;//_c再次使用了10个bit位			15
	int _d : 30;//_d不够用,需要再次开辟4个字节
};

int main()
{
	printf("%d\n", sizeof(struct A));//8个字节
	return 0;
}
//一个例子
struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	printf("%d\n", sizeof(struct S));//3个字节
	struct S s = { 0 };
	s.a = 10;//1010,放进去3bit:010
	s.b = 12;//1100,放进去4bit:1100
	s.c = 3;//11,放进去5bit:00011
	s.d = 4;//100,放进去4个bit:0100

	//0110 0010 0000 0011 0000 0100
	// 先使用低位地址分配,不够继续向高位开辟
	// 0x 6  2    0    3    0    4
	//小端存储模式:040362

	return 0;
}

 

2.3 位段的跨平台问题

  • 1. int 位段被当成有符号数还是无符号数是不确定的。
  • 2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机 器会出问题。
  • 3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  • 4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是 舍弃剩余的位还是利用,这是不确定的。

早期16位机器:sizeof(int) _2个字节

32/64位机器: sizeof(int)_4个字节

总结:

跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。

3. 枚举

枚举顾名思义就是一一列举。

把可能的取值一一列举。

比如我们现实生活中:

一周的星期一到星期日是有限的7天,可以一一列举。

性别有:男、女、保密,也可以一一列举。

月份有12个月,也可以一一列举

3.1 枚举类型的定义

enum Day//枚举类型
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,//枚举常量
	Sun
};
enum Sex//性别
{
	MALE,
	FEMALE,
	SECRET
};

enum Color//颜色
{
	RED,
	GREEN,
	BLUE
};
int main()
{
	enum Sex s = MALE;
	enum Sex s2 = FEMALE;

	return 0;
}

以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。

{}中的内容是枚举类型的可能取值,也叫 枚举常量 。

这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。

例如:

enum Sex//性别
{
	MALE,
	FEMALE,
	SECRET
};

//enum Color//颜色
//{
//	RED,
//	GREEN,
//	BLUE
//};
enum Color//颜色
{
	RED = 1,
	GREEN = 2,//这里叫做常量初始化,并不是修改常量
	BLUE = 4
};

int main()
{
	/*enum Sex s = MALE;
	enum Sex s2 = FEMALE;
	enum Day d = Fri;*/
	printf("%d %d\n", MALE, RED);//0  1

	return 0;
}

这里叫做常量初始化,并不是修改常量

3.2 枚举的优点

为什么使用枚举?

我们可以使用 #define 定义常量,为什么非要使用枚举?

枚举的优点:

1. 增加代码的可读性和可维护性

2. 和#define定义的标识符比较枚举有类型检查,更加严谨。

3. 防止了命名污染(封装)

4. 便于调试

5. 使用方便,一次可以定义多个常量

3.3 枚举的使用

enum Color//颜色
{
	RED = 1,
	GREEN = 2,
	BLUE = 4
};
int main()
{
	enum Color clr = GREEN;//这里会进行类型检查
	//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
	clr = 5;
	printf("%d\n", clr);//5
	return 0;
}

4. 联合(共用体)

4.1 联合类型的定义

联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。

//联合体——共用体
union Un
{
	char c;
	int i;
};
int main()
{
	union Un u;
	printf("%u\n", sizeof(u));//4
	printf("%p\n", &u);//0073FAD8
	printf("%p\n", &(u.c));//0073FAD8
	printf("%p\n", &(u.i));//0073FAD8

	return 0;
}

4.2 联合的特点

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

union Un
{
	char c;
	int i;
};
int main()
{
	union Un u;
	printf("%u\n", sizeof(u));//4
	printf("%p\n", &u);//0073FAD8
	printf("%p\n", &(u.c));//0073FAD8
	printf("%p\n", &(u.i));//0073FAD8
	u.i = 0x11223344;
	u.c = 0x55;
	printf("%x\n", u.i);//11223355
	//联合体使用只使用一次,因为改变了c就会改变i
	//改变了i就会改变c
	return 0;
}

4.2.1 联合体的应用:判断大小端字节序存储模式

//判断大小端
int check_sys()
{
	union Un
	{
		char c;
		int i;
	}u;
	u.i = 1;
	//01 00 00 00 小端
	return u.c;
	//01 
}
int main()
{
	//int i = 1;
	01 00 00 00 小段存储
	//if (*(char*)&i)
	//	printf("小端字节序存储模式\n");
	//else
	//	printf("大端字节序存储模式\n");
	if (1 == check_sys())
		printf("小端\n");
	else
		printf("大端\n");
}

4.3 联合大小的计算

联合的大小至少是最大成员的大小。

当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

 联合体也是存在对齐的

typedef union
{
	char arr[5];//对齐数1
	int i;//对齐数是4 
	//最大对齐数位4,但是arr占5个字节
}Un;
int main()
{
	Un u;
	printf("%u\n", sizeof(u));//8
	return 0;
}
typedef union
{
	short arr[7];//14
	int i;//4
	//最大对齐数是 4  ,但是short占了14个字节
	//因此联合体的大小应该是最大对齐数的整数倍,16
}Un;
int main()
{
	Un u;
	printf("%u\n", sizeof(u));//16
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值