Lesson 22 位段、联合体和枚举

位段

位段与结构体类似,但有2个不同:

  1. 位段成员必须是int、unsigned int、或者 signed int,C99可以选择其它
  2. 位段的成员名之后是一个冒号和一个数字,数字代表其大小(以bit计)
    举个例子:
struct A
{
	int _a:2;
	int _b:5;
	int _c:10;
	int _d:30;
};

以上就是一个位段的声明。

位段的内存分配

  1. 位段是以4个字节或者1个字节来开辟内存空间的;
  2. 位段使用涉及很多不确定因素,跨平台应避免使用位段
    还是用例子来说明吧:
struct S
{
	char a:3;
	char b:4;
	char c:5;
	char d:4;
};
	struct S s = {0};
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;

开辟空间过程如下(VS为例):
a). 首先为a 开辟一个字节的空间(char类型),但a只占其中3个bit,假设初始化为0000 0000
b). b占4个bit,那么接着a之后的4个bit是存放b的;
c). c需要5个bit,第一个字节剩余部分无法容纳c,那么c会再开辟一个字节的空间,然后占用其中的5个bit;
d) d是一样的,剩余部分不够了,因此会再开辟一个字节的空间,占用其中4个bit。
所以开辟的空间就是(假设初始化为0,地址由低到高):

0000 0000 0000 0000 0000 0000

之后赋值的时候:
10写成2进制是1010,但只有3个bit,因此截断,只存010.这样,内存变成了:

00000 010 0000 0000 0000 0000

然后12写成2进制是1100,所以内存:

0 1100 010 0000 0000 0000 0000

然后是3,转换成2进制是011,占据5bit 就是00011

0 1100 010 000 00011 0000 0000

最后是4,二进制是0100,占据4个bit:

0 1100 010 000 00011 0000 0100

那么写成16进制:

0x 62 03 04

位段的跨平台问题

  1. int位段被当成有符号数还是无符号数是不确定的;
  2. 位段中最大位的数目不能确定(16位机器和32位机器);
  3. 位段成员在内存中是从左向右分配还是从右向左分配是不确定的;
  4. 当一个结构体包含位段,第二个位段成员比较大,无法容纳第一个位段剩余的位时,是舍弃还是利用,也是不确定的。

但是,位段可以节约空间。

位段的使用

TCP/IP协议中,IP数据的报文格式就适合使用位段。
位段的几个成员共有一个字节,这样有些成员的起始位置并不是字节的起始位置,那么它就是没有地址的。所以不能对位段的成员使用&操作符。赋值时,先放到一个变量中,然后再赋值。
举例:

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{
	struct A sa = {0};
	scanf("%d", &sa._b);//这是错误的
	//正确的示范
	int b = 0;
	scanf("%d", &b);
	sa._b = b;
	return 0;
}

联合体

像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以是不同的类型。但编译器只为最大的成员分配内存。联合体的特点就是所有成员共用一块内存空间。所以联合体也叫共用体。给联合体一个成员赋值,其余成员的值也跟着变化。

联合体的特点

union UN
{
	char c;
	int i;
};
int main()
{
	union UN un = {0};
	printf("%p",&(un.i));
	printf("%p",&(un.c));
	printf("%p",&un);
	return 0;
}

打印结果是一样的。
赋值会改变另一个成员的值:

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

这里会打印0x11223355

联合体的大小

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

联合体判断大小端

union A
{
	char a;
	int b;
};

int check_sys()
{
	union A test;
	test.b = 1;
	return test.a;
}
int main()
{
	
	if (1 == check_sys())
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

枚举

枚举就是一一列举。把可能的值一一列举出来。
举个例子:

enum Day
{
	MON,
	TUES,
	WED,
	THUR,
	FRI,
	SAT,
	SUN
}

枚举内部可以赋值:

enum Color
{
	RED = 2,
	GREEN = 4,
	BLUE =8
}

枚举的优点

  1. 增加代码的可读性;
  2. 枚举有类型检测,更加严谨;
  3. 便于调试,预处理阶段会删除#define
  4. 使用方便,一次可以定义多个常量;
  5. 枚举常量是遵循作用域规则的。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值