详解自定义类型:结构体,枚举,联合(下)

简介: 详解自定义类型:结构体,枚举,联合(下)

结构体实现位段(位段的填充&可移植性)


什么是位段


位段,C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”( bit field) 。利用位段能够用较少的位数存储数据。

位段和结构体其实是非常相似的,但是有两个不同点:

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

举个例子

1. struct A
2. {
3.  int _a : 2;
4.  int _b : 5;
5.  int _c : 10;
6.  int _d : 30;
7. };

说明:

首先我们要明白位段中的这个“位”字其实指的是二进制位。

我们知道一个二进制位就是1个比特位。

所以,A中int _a : 2;其实表示的就是

_a的大小是2bit;

同理:

_b的大小是5bit

_c的大小是10bit

_d的大小是30bit


位段的内存分配


我们还是用上述代码,我们求一下上述代码的大小

我们惊奇的发现为8,占了8个字节,那么为什么是8呢?

1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型

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

就是说,如果位段的成员全部是整型的(位段成员一般都是同类型的),那上去就先给这个位段开辟4个字节的空间,如果不够用,放不下所有的成员,那就再开辟4个字节的空间,还不够用,继续开辟,以此类推。如果成员全部是char类型的,那就一次开辟1个字节的空间,直至放得下所有成员。

具体分配为:

由于A的成员都是整型(int ),所以一次给A分配4个字节。4个字节是32给比特位,A的前3个成员_a、_b、_c占了17个bit,32-17还剩15bit,但是A的第四个成员_d大小是30bit,而15<30不够。怎么办?再分配4个字节,这下就能放下_d,因此,struct A的大小是4+4=8个字节。

 

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

位段的跨平台问题


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

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

器会出问题。

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

4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是

舍弃剩余的位还是利用,这是不确定的

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


位段的应用


用于IP数据报,格式如下


枚举


枚举顾名思义就是一一列举。 把可能的取值一一列举。

比如我们现实生活中:

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

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

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

这里就可以使用枚举了。

接下来我们举个例子,比如:一星期有 7 天,如果不用枚举,我们需要使用 #define 来为每个整数定义一个别名:

1. #define MON 1
2. 
3. #define TUE 2
4. 
5. #define WED 3
6. 
7. #define THU 4
8. 
9. #define FRI 5
10. 
11. #define SAT 6
12. 
13. #define SUN 7

这个看起来代码量就比较多,接下来我们看看使用枚举的方式:

1. enum DAY
2. {
3.       MON=1, TUE, WED, THU, FRI, SAT, SUN
4. };

这样看起来是不是更简洁了。

注意:第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。


枚举类型的定义


前面我们只是声明了枚举类型,接下来我们看看如何定义枚举变量。

我们可以通过以下三种方式来定义枚举变量

1、先定义枚举类型,再定义枚举变量


1. enum DAY
2. {
3.       MON=1, TUE, WED, THU, FRI, SAT, SUN
4. };
5. enum DAY day;

2、定义枚举类型的同时定义枚举变量

1. enum DAY
2. {
3.       MON=1, TUE, WED, THU, FRI, SAT, SUN
4. } day;

3、省略枚举名称,直接定义枚举变量

1. enum
2. {
3.       MON=1, TUE, WED, THU, FRI, SAT, SUN
4. } day;

枚举的优点


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

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

3. 便于调试

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


枚举的使用

示例一


1. #include <stdio.h>
2. 
3. enum DAY
4. {
5.       MON=1, TUE, WED, THU, FRI, SAT, SUN
6. };
7. 
8. int main()
9. {
10.     enum DAY day;
11. day = WED;
12.     printf("%d",day);
13. return 0;
14. }

输出结果为


示例二


在C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的,所以按照 C 语言规范是没有办法遍历枚举类型的。不过在一些特殊的情况下,枚举类型必须连续是可以实现有条件的遍历。

以下示例使用 for 来遍历枚举的元素:

1. #include <stdio.h>
2. 
3. enum DAY
4. {
5.       MON=1, TUE, WED, THU, FRI, SAT, SUN
6. } day;
7. int main()
8. {
9. // 遍历枚举元素
10. for (day = MON; day <= SUN; day++) {
11.         printf("枚举元素:%d \n", day);
12.     }
13. }

输出结果为

联合(共用体)

联合类型的定义


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

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

比如:


1. //联合类型的声明
2. union Un
3. {
4. char c;
5. int i;
6. };

联合的特点


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

合至少得有能力保存最大的那个成员)。


例如以下代码

1. union Un
2. {
3.  char c;
4.  int i;
5. };
6. 
7. int main()
8. {
9.  printf("%d\n", sizeof(union Un));
10.   union Un un;
11.   printf("%p\n", &un);
12.   printf("%p\n", &(un.i));
13.   printf("%p\n", &(un.c));
14.   return 0;
15. }

我们再看一下运行结果

我们发现联合体大小为 4,而且&un,&(un.i),&(un.c)的地址相同,那么这样即可证明联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小·

联合体的应用


进行系统大小端的判断


代码如下

1. int check_sys()
2. {
3.  union
4.  {
5.    int i;
6.    char c;
7.  }un = {.i = 1};
8.  return un.c;
9. }
10. 
11. int main()
12. {
13.   int ret = check_sys();
14. 
15. 
16.   if (ret == 1)
17.     printf("小端\n");
18.   else
19.     printf("大端\n");
20. 
21.   return 0;
22. }

原理图如下:

博主所用的为小段存储模式,运行结果如下


总结


关于自定义类型就讲解到这儿,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下。

相关文章
|
9月前
|
存储 编译器 C语言
自定义数据类型:结构体,枚举,联合
自定义数据类型:结构体,枚举,联合
|
9月前
|
存储 编译器 Linux
自定义类型——结构体,枚举,联合
自定义类型——结构体,枚举,联合
|
5月前
|
编译器 C++
自定义类型:结构体,枚举,联合
自定义类型:结构体,枚举,联合
|
5月前
|
编译器 C++
自定义类型:结构体,枚举,联合 (1)
自定义类型:结构体,枚举,联合 (1)
45 1
|
5月前
|
存储 编译器 C++
自定义类型:结构体,枚举,联合 (2)
自定义类型:结构体,枚举,联合 (2)
36 0
|
5月前
|
存储 安全 编译器
自定义类型:结构体,枚举,联合
自定义类型:结构体,枚举,联合
85 0
|
6月前
结构体、枚举、联合详解(下)
结构体、枚举、联合详解(下)
17 0
|
编译器 C++
【学习笔记之我要C】自定义类型详解(结构体+枚举+联合)
【学习笔记之我要C】自定义类型详解(结构体+枚举+联合)
274 0
|
10月前
|
编译器 Linux C++
详解自定义类型:结构体,枚举,联合(上)
详解自定义类型:结构体,枚举,联合(上)
|
10月前
|
存储 开发框架 .NET
自定义类型详解(结构体、枚举、联合)(下)
自定义类型详解(结构体、枚举、联合)(下)