梦开始的地方 —— C语言(枚举+位段+联合体)

Posted 爱敲代码的三毛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了梦开始的地方 —— C语言(枚举+位段+联合体)相关的知识,希望对你有一定的参考价值。

位段

1. 什么是位段?

要想了解位段就得先学会使用结构体。文章链接——>详解结构体

位段的声明和结构体是十分类似的,它们有两个不同之处

  1. 位段的成员必须是intunsigned intsigned int
  2. 位段的成员名后面有一个冒号和数字。

定义一个名为test的位段

struct test 
	int a : 2;
	int b : 5;
	int c : 10;
	int d : 30;
;
  • 冒号后面的数字表示该成员占几个比特位(注意有些平台有符号数的符号位也算一个比特位)
  • 比如在VS2019环境,a只有2个比特位00,第一位就是符号,那它只能表示-2~1的数字

那么这个位段test的大小是多少?

printf("%d\\n", sizeof(struct test));

输出是8,也就是8个字节。

  • a占2个比特位,b占5个比特位,从占10个比特位,加起来也就是17个比特位,4个字节就够了
  • 而d需要30个比特位,不够则再开辟一个4个字节的空间
  • 但d是使用前面剩余的一部分加上后面新开辟的空间,还是前面剩余的空间直接浪费使用新开辟的空间这就不得而知了
  • C语言标准并没有规定剩余的空间是否一定要使用

2. 位段的内存分配

  1. 位段的成员变量可以是intunsigned intsigned intchar
  2. 位段的空间上按照需要以4个字节(int),或者是1个字节(char)的方式来开辟的。
  3. 位段存在着很多不确定因素,它是不夸平台的,如果考虑可移植性就要避免使用位段。

举个列子,下面这位段是如何开辟内存的呢?

#include <stdio.h>

struct test 

	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
;
int main()

	struct test t =  0 ;
	t.a = 10;
	t.b = 12;
	t.c = 3;
	t.d = 4; 
	printf("%d\\n", sizeof(struct test));
	return 0;

  • 把10赋值给a,a只有3个比特位,存放010
  • 把12赋值给b,b有4个比特位,存放1100
  • 把3赋值给c,c有5个比特位,存放00011
  • 把4赋值给d,d有4个比特位,在内存中存放0100

VS2019调试环境

通过上面的调试发现

  • 在VS2019平台
  • 前一个空间剩余的比特位不够时,直接浪费,使用新开辟空间的比特位
  • 一个字节内部,是从低位向高位使用的。

3. 位段跨平台问题

前面说过位段的可移植性差,就是因为它的一些不确定因素

  1. int位段被当做有符号数还是无符号数是不确定的
  2. 位段中最大位的数目不能确定(6位机器最大16,32位机器最大32,写成27,在16位机器会出问题 )
  3. 位段中的成员变量在内存中分配空间,是从左向右分配还是从右向左分配,C语言标准也未定义。
  4. 当一个结构体包含两个位段,第二个位段成员比较大,前一个位段开辟空间剩余的比特位不够时,是浪费剩余的位,还是用掉剩余的再加上新开辟的空间,C语言标准也是未定义的。

4. 位段的应用

这是ipv4首部的一张图,网络传输要保证正确的同时还要保证速度,把每一个字段精确的设计,可以避免没有必要的浪费,就能让数据包尽可能的小,提高传输效率。

联合(共用体)

1. 联合类型的定义

联合是一种特殊的自定义类型,它也和结构体类似,也可以包含一系列成员,特征是这些成员共用同一块内存空间,所以叫做联合也可以叫做共用体。

通过union关键字定义一个联合类型

#include <stdio.h>

union User

	int id;
	char ch;
;
int main()

	union User u;
    
	return 0;


2. 联合的特点

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

来看一段代码

#include <stdio.h>

union User

	int id;
	char ch;
;
int main()

	union User u;
	printf("%p\\n", &(u.id));
	printf("%p\\n", &(u.ch));


	return 0;

打印结果

006FF8B0
006FF8B0

发现这两个成员变量果然用的是同一块内存空间。

再来看一段代码验证一下

#include <stdio.h>

union User

	int id;
	char ch;
;
int main()

	union User u;
	u.id = 0x11223344;
	u.ch = 0x55;
	printf("%x\\n", u.id);



	return 0;

打印结果

11223355
  • 因为我们这里是VS2019-X86环境,是小端存储
  • 联合的成员变量共用一块内存,那么ch在赋值的时候就会覆盖掉id的值

通过联合也可以判断大小端

  • 如果是小端,ch拿 的是低位的地址就能拿到1
  • 如果是大端,高位存低位,低位存高位,拿么ch拿低位拿到的就是0
#include <stdio.h>

union User

	int id;
	char ch;
;
int main()

	union User u;
	u.id = 1;
	if (u.id)
	
		printf("小端\\n");
	
	else
	
		printf("大端\\n");
	


	return 0;

3. 联合大小的计算

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

来看一个列子

#include <stdio.h>

union u1

	char arr[5];//5
	int a;//4
;
union u2

	short arr[7];//7
	int a;//4
;
int main()

	printf("%d\\n", sizeof(union u1));//
	printf("%d\\n", sizeof(union u2));//

	return 0;

打印结果

8
16
  • 联合中,数组大对齐数是它的成员对齐数,所以char arr[5]的对齐数是1
  • a是一个整形它的对齐数是4,所以该联合的最大对齐数是4
  • 但arr数组大小是5,当最大成员大小不是最大对齐数整数倍的时候,就要对齐到最大对齐数的整数倍
  • 所以对齐到最大对齐数4的整数倍8

联合类型u2

  • short arr[7],该数组大小是14,它的对齐数是数组中的成员也就是2
  • a的对齐数是4,而14不是4的倍数,要对齐到4的倍数16

所以联合的大小至少是最大成员的大小,但不一定是最大成员的大小,还要考虑到最大对齐数对齐

枚举

枚举:顾名思义就是一个一个列举。当我们有些类型,不适合用基本类型来,描述的时候就可以使用枚举。

1. 枚举的定义

通过enum关键字来定义枚举类型,用枚举来描述一个三原色

enum RGB

	RED,
	GREEN,
	BLUE
;

RGB就是自定义的枚举类型,枚举类型的成员是有初始值的,默认从0开始

#include <stdio.h>

enum RGB

	RED,
	GREEN,
	BLUE
;

int main()

	printf("%d\\n",RED);
	printf("%d\\n",GREEN);
	printf("%d\\n",BLUE);


	return 0;

打印结果

1
2
3

当然也可以修改默认值

#include <stdio.h>

enum RGB

	RED = 10,
	GREEN = 15,
	BLUE
;

int main()

	printf("%d\\n",RED);
	printf("%d\\n",GREEN);
	printf("%d\\n",BLUE);


	return 0;

打印结果

10
15
16

2. 为什么要使用枚举常量

枚举可以做到事情#define也可以做到,为什么要使用枚举?

枚举的一些优点

  • 增加代码的可维护性和可读性
  • 枚举具有类型检查,而#define没有
  • 定义方便,一次可以定义多个常量,而#define一次只能定义一个
  • 方便调试,#define是不能调试的,#define在预编译阶段就把对应的值给替换了
#include <stdio.h>

enum RGB

	RED = 10,
	GREEN = 15,
	BLUE
;

int main()

	enum RGB color = RED;
	printf("%d\\n", color);


	return 0;



以上是关于梦开始的地方 —— C语言(枚举+位段+联合体)的主要内容,如果未能解决你的问题,请参考以下文章

C语言☀️自定义类型(结构体+位段+枚举+联合体)建议收藏

“解剖”c语言——自定义类型(结构体,位段,枚举,联合体)

c语言篇 +自定义类型(枚举联合结构体)以及位段

C语言自定义数据类型:结构体,枚举,联合

C语言自定义数据类型:结构体,枚举,联合

C语言自定义数据类型:结构体,枚举,联合