【C语言进阶】结构体、位段、枚举、以及联合(共用体)的相关原理与使用(下)

简介: 【C语言进阶】结构体、位段、枚举、以及联合(共用体)的相关原理与使用(下)

至此,该位段结构的内存分配结束,共占据3个char 类型数据的大小,即 3 个字节

2.3 位段的跨平台问题:

我们上面说过,位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段,并且在未来位段结构的使用过程中,我们一定要提前仔细地研究好位段在不同编译器下使用时,究竟是如何进行内存分配的,再结合我们的实际需求实现跨平台使用。

而在位段进行跨平台使用时,我们通常需要注意以下四个关键点:

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

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

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

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


总结下来,跟结构相比,位段可以达到跟结构相同的效果,并且可以更好的利用空间,但同时存在着跨平台问题

3.枚举

枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数这两种类型经常但不总是重叠。是一个被命名的整型常数的集合。简单来说就将某种特定类型的对象一一进行列举。

枚举的声明与结构和联合相似, 其形式为:

enum 枚举名{

标识符(=整型常数),

标识符(=整型常数),

标识符(=整型常数)

} 枚举变量;

3.1 定义:

#include<stdio.h> 
//枚举类型1:
enum Sex
{
  MALE,
  FEMALE,
  SECRET
}s1 = MALE;
//声明时进行定义与初始化(全局)
enum Sex s2 = FEMALE;
//枚举类型2:
enum Day
{
  Mon,
  Tues,
  Wed,
  Thur,
  Fri,
  Sat,
  Sun
};
int main()
{
  enum Day s3 = Mon;
  //定义与初始化(局部)
  return 0;
}

我们可以看到,枚举类型的声明、定义与初始化与结构十分类似。然后我们再来看一看枚举类型内部各成员的值,我们以日期为例:

#include<stdio.h>
enum Day
{
  Mon,
  Tues,
  Wed,
  Thur,
  Fri,
  Sat,
  Sun
};
int main()
{
    //打印各成员的值:
  printf("The value of Mon  is %d\n", Mon);
  printf("The value of Tues is %d\n", Tues);
  printf("The value of Wed  is %d\n", Wed);
  printf("The value of Thur is %d\n", Thur);
  printf("The value of Fri  is %d\n", Fri);
  printf("The value of Sat  is %d\n", Sat);
  printf("The value of Sun  is %d\n", Sun);
  return 0;
}

将上面这个示例编译运行起来看看结果的反馈:

d42a2a580abe409abb637449d0a12969.png我们看到,枚举类型内部各成员的默认值是从 0 开始依次递增的。

但是成员的值不仅限于默认值,同时也允许我们在定义时给各成员附合适的初值:

#include<stdio.h>
enum Day
{
  Mon,
  Tues=5,
  Wed,
  Thur,
  Fri,
  Sat=15,
  Sun
};
int main()
{
  printf("The value of Mon  is %d\n", Mon);
  printf("The value of Tues is %d\n", Tues);
  printf("The value of Wed  is %d\n", Wed);
  printf("The value of Thur is %d\n", Thur);
  printf("The value of Fri  is %d\n", Fri);
  printf("The value of Sat  is %d\n", Sat);
  printf("The value of Sun  is %d\n", Sun);
  return 0;
}

a201a7ac84de4fa89e85b845fb5724cc.png我们可以依照上面这种方式对枚举类型成员的初值进行修改:

我们看到,经过修改本应按序赋值为 1 的枚举成员 Tues 被赋值成了 5 ,于是接下来的成员就从 5 开始依次赋值,直到成员 Sat 被赋值为 15 后,接下来的成员就从 15 开始依次递增。

3.2 枚举类型的优点:

枚举类型的成员均为常量,不可在使用中被修改,那么我们同样可使用宏 #define 去定义常量,为什么非要使用枚举类型呢?

这是因为,相比于宏,枚举类型具有很多优点:

优点:

  1. 增加代码的可读性和可维护性。
  2. 和 #define 定义的标识符相比较,枚举有类型检查,更加严谨。
  3. 防止了命名污染(通过封装实现)。
  4. 便于调试。
  5. 使用方便,一次可以定义多个常量。

3.3 枚举类型的使用:

同时我们要注意,在使用枚举类型时只能用枚举常量给枚举变量赋值,只有这样才不会出现类型差异:

#include<stdio.h> 
//声明枚举类型
enum TEST
{
  test1,
  test2,
  test3
};
//其中test1、test2、test3为枚举常量
int main()
{
  //定义枚举变量:
  enum TEST t;
  //使用枚举常量给枚举变量赋值:
  t = test3;
  //验证赋值结果:
  printf("The value of t is %d\n", t);
  return 0;
}

4.联合(共用体)

在进行某些算法的编程的时候,需要将几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术使几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作 “ 联合体 ” 类型结构,简称联合,也叫共用体。

4.1 联合类型的定义:

联合是一种特殊的自定义类型,这种类型定义的变量也包含有一系列的成员,但不同的是这些成员共用同一块空间(也被称作共用体)

它的定义也基本与结构体一致:

#include<stdio.h>
union TEST
{
  char a;
  int b;
}test;
//在定义联合体的同时定义联合体变量test
int main()
{
  //查看联合体的占用空间:
  printf("The size of test is %d\n", sizeof(test));
  //查看联合体成员的存储地址:
    printf("The address of test is %p\n", &test);
  printf("The address of   a  is %p\n", &test.a);
  printf("The address of   b  is %p\n", &test.b);
  return 0;
}

ff411d17fe504354bf5984bb880be5e3.png但不同的是,我们编译运行后发现,联合体成员 char 类型变量 a 与 int 类型变量 b 共同占用同一片空间(一个 int 类型所占的空间):

这种方式定义的联合体结构,是三种结构中最节省空间的一种,但同时,极致的空间节省能力导致了它在使用时需要满足的条件极为苛刻。

4.2 联合类型的特点:

联合体最大的特点就是,联合体的成员是共用同一块内存空间的,则联合至少得有足够的空间容纳最大的成员,这样一个联合变量的大小就至少得是最大成员的大小。既然联合体的大小会随着内部成员大小的变化而变化,那么是不是联合体类型也可以通过判断内容大小,来帮助我们判断机器的大小端存储模式呢?

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int check_sys()
{
  union CHECK
  {
    char check1;
    int check2;
  }check;
  check.check2 = 1;
  return check.check1;
}
int main()
{
  if (1 == check_sys())
  {
    printf("您的机器采用小端存储模式!\n");
  }
  else
  {
    printf("您的机器采用大端存储模式!\n");
  }
  return 0;
}

fe994c1126054c0a8a80e6af12fc9134.png我们将其编译运行发现,该思路可以帮助我们检查机器的大小端存储模式

4.3 联合类型大小的计算:

联合体类型的大小计算需要按照以下规则进行计算

  1. 联合的大小至少是最大成员的大小。
  2. 当最大成员大小不是最大对齐数的整数倍时,要对齐到最大对齐数的整数倍。
#include<stdio.h>
//联合体1:
union TEST1
{
  char c[5];
  int i;
};
//联合体2:
union TEST2
{
  short c[7];
  int i;
};
int main()
{
  //检查联合体的大小:
  printf("The size of TEST1 is %d\n", sizeof(union TEST1));
  printf("The size of TEST2 is %d\n", sizeof(union TEST2));
  return 0;
}

1.在联合体 TEST1 中,占用空间最大的成员是 char 类型数组 c ,且其中含有 5 个元素,则其所占空间大小为 5 个字节,而我们都知道 VS 的对齐数默认为 8 ,则将会对齐至默认对齐数的整数倍,即 8 个字节。

2.而联合体 TEST2 中,占用空间最大的成员是 short 类型数组 c ,且其中含有 7 个元素,则其所占空间的大小为 14 个字节,那么就将会对齐至对齐数的整数倍,即 16 个字节

5.总结:

今天我们对结构体的相关原理与使用等知识又有了新的了解,学习了结构体、位段、枚举、以及联合(共用体)的相关知识,完成了通过联合体类型判断机器的大小端存储模式,希望我的文章和讲解能对大家的学习提供一些帮助。


当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

c3ad96b16d2e46119dd2b9357f295e3f.jpg

相关文章
|
11天前
|
C语言
【C语言程序设计——循环程序设计】枚举法换硬币(头歌实践教学平台习题)【合集】
本文档介绍了编程任务的详细内容,旨在运用枚举法求解硬币等额 - 循环控制语句(`for`、`while`)及跳转语句(`break`、`continue`)的使用。 - 循环嵌套语句的基本概念和应用,如双重`for`循环、`while`嵌套等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台将对编写的代码进行测试,并给出预期输出结果。 5. **通关代码**:提供完整的代码示例,帮助理解并完成任务。 6. **测试结果**:展示代码运行后的实际输出,验证正确性。 文档结构清晰,逐步引导读者掌握循环结构与嵌套的应用,最终实现硬币兑换的程序设计。
42 19
|
11天前
|
C语言
【C语言程序设计——枚举】得到 3 种不同颜色的球的可能取法(头歌实践教学平台习题)【合集】
本关任务要求从红、黄、蓝、白、黑五种颜色的球中,每次取出3个不同颜色的球,列举所有可能的排列情况。通过定义枚举类型和使用嵌套循环语句实现。枚举类型用于表示球的颜色,循环语句用于生成并输出所有符合条件的排列 编程要求:在指定区域内补充代码,确保输出格式正确且完整。测试说明:平台将验证代码输出是否与预期一致,包括每种排列的具体顺序和总数。 示例输出: ``` Output: 1 red yellow blue 2 red yellow white ... 60 black white blue total: 60 ```
31 4
|
1月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
163 14
|
1月前
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
195 10
|
2月前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
2月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
215 13
|
2月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
84 11
|
2月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
68 4
|
3月前
|
存储 C语言
如何在 C 语言中实现结构体的深拷贝
在C语言中实现结构体的深拷贝,需要手动分配内存并逐个复制成员变量,确保新结构体与原结构体完全独立,避免浅拷贝导致的数据共享问题。具体方法包括使用 `malloc` 分配内存和 `memcpy` 或手动赋值。
105 10
|
3月前
|
存储 大数据 编译器
C语言:结构体对齐规则
C语言中,结构体对齐规则是指编译器为了提高数据访问效率,会根据成员变量的类型对结构体中的成员进行内存对齐。通常遵循编译器默认的对齐方式或使用特定的对齐指令来优化结构体布局,以减少内存浪费并提升性能。

热门文章

最新文章