C语言自定义类型-----位段,枚举,联合(共用体)

一、位段

位段和结构体的声明类似

struct A
{
	unsigned char a : 3;
	unsigned char b : 4;
	unsigned char c : 5;
	unsigned char d : 4;
};

这里我们声明了一个位段类型A,与结构体不同的是,每个成员后面都有一个冒号且都跟一个数字,其含义是该成员占用几个比特位。

位段的内存分配
  • 位段的成员可以是int 、unsigned int、signed int、或者是char(属于整型家族)类型。
  • 位段的空间上按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。
    在这里插入图片描述

该例子中,struct A类型的位段一共占3个字节。

位段的使用

其他和结构体类似,可以对成员进行赋值使用。

struct A
{
	unsigned char a : 3;
	unsigned char b : 4;
	unsigned char c : 5;
	unsigned char d : 4;
};
int main()
{
	struct A s = { 0 };
	s.a = 1;
	s.b = 2;
	s.c = 3;
	s.d = 4;
	printf("%d\n",sizeof(s));
	printf("%u %u %u %u\n",s.a,s.b,s.c,s.d);
	system("pause");
	return 0;
}

在这里插入图片描述

位段存在的问题
  • 位段主要存在跨平台问题,在不同的环境下,最大比特位数不确定,如16位机器最大位是16(一次最大开辟16个比特位),32位机器最大位是32,在32位机器下可以要到27个比特位,但是16位就不行。
  • 位段中的成员在内存中是从左向右分配,还是从右向左分配标准尚未定义(例子中假设从右向左分配)
  • 当一个结构中第一个字节剩余的比特位是要利用起来还是舍弃还不确定(例子中舍弃)

二、枚举

枚举的定义
enum color
{
	RED,
	QRANGE,
	YELLOW,
	GREEN,
	BLUE,
	WHIET,
	BLACK,
};

这里我们定义了枚举类型color,里面共有7个成员。

枚举的使用
enum color
{
	RED,
	QRANGE,
	YELLOW,
	GREEN,
	BLUE,
	WHIET,
	BLACK,
};
int main()
{
	enum color c = YELLOW;
	system("pause");
	return 0;
}

这里创建了一个enum color类型变量c,它只可以被赋值为enum color里面的成员之一。

  • 本质上来说enum里面的成员都是整型。
enum color
{
	RED,
	QRANGE,
	YELLOW,
	GREEN,
	BLUE,
	WHIET,
	BLACK,
};
int main()
{
	printf("%d\n", RED);
	printf("%d\n", QRANGE);
	printf("%d\n", YELLOW);
	printf("%d\n", GREEN);
	printf("%d\n", BLUE);
	printf("%d\n", WHIET);
	printf("%d\n", BLACK);
	system("pause");
	return 0;
}

在这里插入图片描述

  • enum中默认第一个成员的值为0,往后依次递增,当然,我们也可以赋初值。
enum color
{
	RED = 1,
	QRANGE,
	YELLOW,
	GREEN = 10,
	BLUE,
	WHIET,
	BLACK,
};

这都是可以的,往后成员依次递增,但是为了方便,一般成员的值都是连续的。

  • 枚举和宏定义差不太多,使用层面上也没什么区别。
  • 使用时如果要声明的常量少且互相没有关联,就用宏,如果要声明的常量多且互相关联,就使用枚举

联合

联合的定义
union  un
{
	char c;
	int i;
};

这里定义了一个联合类型un,共包含两个成员,char c和int i;

联合的使用

使用上和结构体一样,也用’.'操作符。

union  un
{
	char c;
	int i;
};
int main()
{
	union un a = { 0 };
	a.i = 5;
	printf("%d\n".a.i);
	system("pause");
	return 0;
}
联合的内存分配

在内存分配上,联合和结构体就有所不同了,联合的所有成员共享空间。
就是联合会开辟一块内存,所有成员共享,所以联合内的成员的起始地址都一样。

union  un
{
	char c;
	int i;
};
int main()
{
	union un a = { 0 };
	printf("%p\n",&a);
	printf("%p\n",&(a.c));
	printf("%p\n",&(a.i));
	system("pause");
	return 0;
}

在这里插入图片描述
所以我们也可以看到这样的操作。

union  un
{
	char c;
	int i;
};
int main()
{
	union un a = { 0 };
	a.i = 1;
	printf("%d\n",a.c);
	system("pause");
	return 0;
}

在这里插入图片描述
这可以用来验证电脑是大端存储还是小端存储(例子中是小端)。

联合的大小

我们来看一个例子

union  un
{
	char a[7];
	int i;
};
int main()
{
	printf("%d\n",sizeof(union un));
	system("pause");
	return 0;
}

在这里插入图片描述
所以,计算联合的大小时也要注意内存对齐问题。

  • 联合的大小至少是最大成员的大小
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
  • 对齐数 = 编译器默认对齐数与该成员大小的较小值(vs默认8,Linux默认4);如果是聚合数据类型(数组和结构体),对齐数为该聚合类型中成员的最大对齐数。
    在例子中,最大成员的大小是7字节,但是最大对齐数是4,7不能整除4,所以最终大小为8字节。
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值