C语言进阶——自定义类型——位段、枚举、联合

结构体


目录

一.   位段

1.概念

2.位段的内存分配

3.位段的跨平台问题

4.位段的应用

二.   枚举

1.枚举类型的定义

2.枚举的优点

3.枚举的使用

三.   联合(共用体)

1.联合类型的定义

​编辑

2.联合的特点

3. 联合大小的计算


一.   位段

1.概念

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

1.位段的成员必须是 int、unsigned int 、signed int或char(本质上也属于整形) 。

2.位段的成员名后边有一个冒号和一个数字,而这个数字表示的是所占的二进制位数

例如

struct A
{
    int _a:2;
    int _b:5;
    int _c:10;
    int _d:30;
};

2.位段的内存分配

位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。

后面的数字不能大于类型的大小

位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

int main()
{
    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;
    return 0;
}

我们就用上面这代码来研究一下位段是如何进行内存分配的

首先,每个字节都有8位 

 顺着来看一下,首先是a,首先写出10的补码  00001010,然后将前三位(010)截断放进去

 然后是b, 12的补码是00001100,将前四位(1100)截断放进去

然后是c,3的补码是00000011,将前五位(00011)放进去,但我们可以看到,这一个字节只剩下一位了,放不开五位,根据编译器的不同,有的会先存满这个字节,再存下一个字节,而有的会直接在下一个字节存储,而我使用的vs2022是第二种方式

 最后的d也一样

 最后就是这个样子

 int 也差不多


3.位段的跨平台问题

1. int 位段被当成有符号数还是无符号数是不确定的。

2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。)

3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的


4.位段的应用



二.   枚举

枚举顾名思义就是一一列举,把可能的取值一一列举。在之前的学习中也大致的提到过

1.枚举类型的定义

enum Color
{
    RED,
    GREEN,
    BLUE
};

就是这么定义的

第一个取值默认为0,后面依次递增1,当然,我们可以改变任何位置的值,后面依旧是依次递增1


2.枚举的优点

枚举的优点:

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

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

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

4. 便于调试

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


3.枚举的使用

只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。

enum Color//颜色
{
RED=1,
GREEN=2,
BLUE=4
};
enum Color clr = GREEN;//right
clr = 5; //error


三.   联合(共用体)

1.联合类型的定义

联合也是一种特殊的自定义类型

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

例如

int main()
{
	union Un
	{
		char c;
		int i;
	};
	union Un un;
	printf("%p\n", &(un.i));
	printf("%p\n", &(un.c));
}

可以看到,两个成员的地址是相同的,这也就证实了成员是公用同一块空间的 


2.联合的特点

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

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



可以看到,在成员c改变时,i也会跟着改变

因此,我们也可以利用这一点来判断机器是大端还是小端

类似于上面,便是小端,而若是55223344,便是大端


3. 联合大小的计算

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

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

第一点很好理解,毕竟联合的大小必须能够存放下每个成员

而第二点,举个例子

	union Un
	{
		int i;
		char c[5];
	};

这个联合,最大的成员大小应该是c的5个字节,而最大对齐数应该是4(int),这时,我们便需要进行对齐,大小则应该为8









 

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

finish_speech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值