【C语言】自定义类型讲解

news2025/3/11 0:03:01

文章目录

  • 一、前言
  • 二、结构体
    • 2.1 概念
    • 2.2 定义
      • 2.2.1 通常情况下的定义
      • 2.2.2 匿名结构体
    • 2.3 结构体的自引用和嵌套
    • 2.4 结构体变量的定义与初始化
    • 2.5 结构体的内存对齐
    • 2.6 结构体传参
    • 2.7 结构体实现位段
  • 三、枚举
    • 3.1 概念
    • 3.2 定义
    • 3.3 枚举的优点
      • 3.3.1 提高代码的可读性
      • 3.3.2 防止非法值
      • 3.3.3 方便维护
    • 3.4 枚举的使用
      • 3.4.1 基础使用
      • 3.4.2 搭配switch使用
      • 3.4.3 使用typedef简化枚举类型
  • 四、联合体
    • 4.1 概念
    • 4.2 定义
    • 4.3 联合体的特点
    • 4.4 联合体的使用
      • 4.4.1 基础使用
      • 4.4.2 联合体的内存大小
    • 4.5 应用场景

一、前言

本文主要是讲解C语言中的自定义类型,包括:结构体、枚举、联合体。

二、结构体

2.1 概念

在C语言中,结构体是一种强大的数据组织工具,它允许我们将不同类型的数据组合在一起,形成一个逻辑上的整体。通过合理使用结构体,可以提高代码的可读性、可维护性和复用性。

2.2 定义

2.2.1 通常情况下的定义

struct Book
{
  char name[20];
  int price;
  char id[12];
}b1,b2;

2.2.2 匿名结构体

匿名结构体通常用于一些临时性的、不需要多次使用的数据结构。由于没有类型名称,匿名结构体变量只能在声明它的作用域内使用。

struct
{
    char name[20];
    int price;
    char id[12];
}s;

2.3 结构体的自引用和嵌套

结构体可以包含自身类型的成员,这种特性称为自引用。例如,我们可以定义一个链表节点结构体,其中包含一个指向相同结构体类型的指针:

struct Node
{
    int data;
    struct Node* next;
};

2.4 结构体变量的定义与初始化

struct Book b1 = {"C Programming", 50, "123456789012"};

这里,b1是一个Book类型的结构体变量,并且在定义时初始化了它的所有成员。如果只初始化部分成员,未初始化的成员将自动初始化为零(对于数值类型)或空字符串(对于字符数组)。

2.5 结构体的内存对齐

在C语言中,结构体的内存布局受到内存对齐规则的影响。内存对齐的目的是提高数据访问的效率。以下是结构体内存对齐的一些基本规则:

  1. 第一个成员的对齐:结构体的第一个成员放在结构体变量在内存中存储位置的0偏移处开始。
  2. 后续成员的对齐:从第二个成员往后的所有成员,都放在一个对齐数(成员的大小和默认对齐数的较小值)的整数倍的地址处。
  3. 结构体总大小的对齐:结构体的总大小是结构体的所有成员的对齐数中最大的那个对齐数的整数倍。
  4. 嵌套结构体的对齐:如果结构体中嵌套了其他结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

第二点规则的例子:

struct Example
{
    char a;      // 1字节
    short b;     // 2字节
    int c;       // 4字节
    char d;      // 1字节
};

此时,内存应该如下图对齐:

把成员调换一下

struct Example
{
    char a;      // 1字节
    int c;       // 4字节
    short b;     // 2字节
    char d;      // 1字节
};

如下图:

2.6 结构体传参

在函数调用中,结构体变量可以作为参数传递。由于结构体可能包含多个成员,直接传递结构体变量可能会导致较大的内存拷贝开销。因此,建议在传递结构体时使用指针。例如:

void printBook(struct Book* book)
{
    printf("Name: %s\n", book->name);
    printf("Price: %d\n", book->price);
    printf("ID: %s\n", book->id);
}

struct Book b1 = {"C Programming", 50, "123456789012"};
printBook(&b1);

2.7 结构体实现位段

位段是一种特殊的结构体成员,它允许我们指定成员占用的位数。位段通常用于硬件编程或需要精确控制内存布局的场景。例如:

struct S
{
    char a : 3; // a占3个bit
    char b : 4;
    char c : 5;
    char d : 4;
};

struct S s;
s.a = 7; // 二进制为0111
s.b = 15; // 二进制为1111

在这个例子中,a、b、c和d是位段成员,分别占用3、4、5和4个位。位段的空间是按照需要以4个字节(int)或者一个字节(char)的方式来开辟的。

三、枚举

3.1 概念

在C语言中,枚举(enum)是一种用户自定义的整数类型,它允许为整数值赋予有意义的名称。枚举类型通常用于表示一组相关的常量,使代码更具可读性和易维护性。

3.2 定义

默认是从0开始。

enum 枚举名 {
    枚举值1,
    枚举值2,
    枚举值3,
    ...
};

例如,以下代码定义了一个表示一周七天的枚举类型Day,也可以自定义mon的值,这样它会根据最上面的值往下递增:

enum Day{
    Mon = 1,
    Tues,
    Wed,
    Thur,
    Fri,
    Sat,
    Sun
};

3.3 枚举的优点

3.3.1 提高代码的可读性

枚举类型通过为整数值赋予有意义的名称,使代码更易于理解和维护。例如,使用枚举类型Day时,代码可以写成:

enum Day today = Fri;

3.3.2 防止非法值

枚举类型限制了变量可以取的值,从而防止非法值的赋值。例如,today变量只能取Mon到Sun中的某个值,而不能是其他任意整数。这有助于减少潜在的错误。

3.3.3 方便维护

当需要添加新的枚举值时,只需在枚举定义中添加新的名称,而无需修改其他代码。例如,如果需要添加一个表示“节假日”的枚举值,只需在Day中添加:

enum Day{
    Mon = 1,
    Tues,
    Wed,
    Thur,
    Fri,
    Sat,
    Sun,
    Holiday
};

3.4 枚举的使用

3.4.1 基础使用

enum Day{
	Mon = 1,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

int main()
{
	enum Day today = Mon;
	printf("today is %d\n", today);
	return 0;
}

3.4.2 搭配switch使用

enum Day{
	Mon = 1,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

int main()
{
	/*模拟键盘输入 */
	enum Day today = Mon;

	switch (today) {
		case Mon:
			printf("Today is Monday\n");
			break;
		case Tues:
			printf("Today is Tuesday\n");
			break;
		case Wed:
			printf("Today is Wednesday\n");
			break;
		case Thur:
			printf("Today is Thursday\n");
			break;
		case Fri:
			printf("Today is Friday\n");
			break;
		case Sat:
			printf("Today is Saturday\n");
			break;
		case Sun:
			printf("Today is Sunday\n");
			break;
		default:
			printf("Unknown day\n");
	}
	return 0;
}

3.4.3 使用typedef简化枚举类型

typedef enum Day{
	Mon = 1,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
}Day_t;

int main()
{
	/*模拟键盘输入 */
	Day_t today = Sat;

	switch (today) {
		case Mon:
			printf("Today is Monday\n");
			break;
		case Tues:
			printf("Today is Tuesday\n");
			break;
		case Wed:
			printf("Today is Wednesday\n");
			break;
		case Thur:
			printf("Today is Thursday\n");
			break;
		case Fri:
			printf("Today is Friday\n");
			break;
		case Sat:
			printf("Today is Saturday\n");
			break;
		case Sun:
			printf("Today is Sunday\n");
			break;
		default:
			printf("Unknown day\n");
	}
	return 0;
}

四、联合体

4.1 概念

在C语言中,联合体也叫共用体,联合体(Union)是一种特殊的数据结构,它允许在同一内存位置上存储不同类型的变量。换句话说,联合体中的所有成员都共享同一块内存空间,因此,联合体的大小是它最大成员所需的内存空间。联合体是一种有效的内存使用方式,尤其是在我们需要在不同时间点使用不同类型的数据时。

4.2 定义

在C语言中,联合体的定义使用关键字 union。与结构体不同,结构体中的每个成员都有自己的内存空间,而联合体中的所有成员共用同一块内存。其基本定义格式如下:

union Un {
    char c;
    int i;
};

在上述代码中,Un 是联合体的名字,c 和 i 是该联合体的成员。虽然它有两个成员,一个是字符型 char,另一个是整型 int,但是这两个成员是共享内存的。也就是说,它们存储的数据会覆盖彼此。

4.3 联合体的特点

  1. 共用内存:联合体的成员共享同一块内存,所有成员的起始地址相同。因此,每次只能存储一个成员的数据。修改一个成员的值会影响其他成员,因为它们共用同一块内存。
  2. 大小:联合体的大小由其最大成员的大小决定。即使联合体中有多个成员,它的大小将是最大的成员所占内存的大小。举个例子,在上述定义中,char 通常占 1 字节,int 通常占 4 字节,因此该联合体的大小通常是 4 字节(由 int 决定)。
  3. 内存优化:联合体提供了内存优化的功能,尤其适用于当某个变量需要存储不同类型的数据,但在同一时刻只需要存储其中一个数据时。例如,保存一个变量可能是整数,也可能是字符值,根据需要使用不同类型的数据时,使用联合体可以节省内存空间。

4.4 联合体的使用

4.4.1 基础使用

union Un
{
	char c;
	int i;
};


int main()
{
	union Un u;
	u.c = 'A';
	u.i = 100;
	printf("c=%c i=%d\n", u.c, u.i);
	return 0;
}

此时,c=d i=100。

分析一下代码执行过程,首先u.c = ‘A’;此时联合体的内存内容是0x41。然后,u.i = 100;假设此时是小端模式则内存的内容是0x64。联合体是共享内存的所以u.c的内容已经被覆盖掉,char类型是一个字节,所以此时这个字节里面的内容用十进制表示就是100用ascii值表示就是d。

4.4.2 联合体的内存大小

#include <stdio.h>

union Un {
    char c;
    int i;
};

int main()
{
    union Un u;
    printf("Size of union Un: %zu bytes\n", sizeof(u));
    return 0;
}

根据上述代码,输出的联合体大小通常为 4 字节(这取决于系统架构)。这是因为 int 类型通常占 4 字节,而 char 占 1 字节。由于联合体共享内存,所以联合体的大小是最大成员(int 类型)所占的字节数。

4.5 应用场景

  1. 节省内存:当我们需要存储多种数据类型,但在某一时刻只需要其中之一时,使用联合体可以有效节省内存。例如,在编写操作系统或硬件驱动时,联合体常用于存储可能是不同类型的寄存器值。
  2. 类型转换:在一些需要类型转换的场合,联合体常被用作一种简便的方式来查看和修改不同数据类型的内存表示。例如,可以用联合体来将一个 float 类型的值解释为 int 类型的位表示,反之亦然。
#include <stdio.h>

union Converter {
    float f;
    int i;
};

int main()
{
    union Converter c;

    // 将 float 类型的值存储在联合体中
    c.f = 3.14f;

    // 打印 float 类型的值
    printf("Float value: %f\n", c.f);

    // 打印相应的 int 类型位表示
    printf("Int representation (as bits): %d\n", c.i);

    // 将 int 类型值赋给联合体的 i 成员
    c.i = 1078523331;  // 通过 int 位表示修改 float 值

    // 打印修改后的 float 值
    printf("Modified float value: %f\n", c.f);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2292339.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LabVIEW涡轮诊断系统

一、项目背景与行业痛点 涡轮机械是发电厂、航空发动机、石油化工等领域的核心动力设备&#xff0c;其运行状态直接关系到生产安全与经济效益。据统计&#xff0c;涡轮故障导致的非计划停机可造成每小时数十万元的经济损失&#xff0c;且突发故障可能引发严重安全事故。传统人…

Kubernetes 中 BGP 与二层网络的较量:究竟孰轻孰重?

如果你曾搭建过Kubernetes集群&#xff0c;就会知道网络配置是一个很容易让人深陷其中的领域。在负载均衡器、服务通告和IP管理之间&#xff0c;你要同时应对许多变动的因素。对于许多配置而言&#xff0c;使用二层&#xff08;L2&#xff09;网络就完全能满足需求。但边界网关…

大模型综述一镜到底(全文八万字) ——《Large Language Models: A Survey》

论文链接&#xff1a;https://arxiv.org/abs/2402.06196 摘要&#xff1a;自2022年11月ChatGPT发布以来&#xff0c;大语言模型&#xff08;LLMs&#xff09;因其在广泛的自然语言任务上的强大性能而备受关注。正如缩放定律所预测的那样&#xff0c;大语言模型通过在大量文本数…

物理群晖SA6400核显直通win10虚拟机(VMM)

写在前面&#xff1a;请先确保你的核显驱动支持开启SR-IOV 确保你的BIOS开启了以下选项&#xff1a; VT-D VMX IOMMU Above 4G ResizeBAR 自行通过以下命令确认支持情况&#xff1a; dmesg | grep -i iommudmesg | grep DMAR分配1个虚拟vGPU&#xff1a;echo 1 | sudo tee /sy…

【python】tkinter实现音乐播放器(源码+音频文件)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、测试技术。 【python】tkinter实现音乐播放器&#xff08;源码…

MyBatis-Plus速成指南:常用注解

Table Name: 概述&#xff1a; MyBatis-Plus 在确定操作的表时&#xff0c;由 BaseMapper的泛型决定&#xff0c;即实体类决定&#xff0c;且默认操作的表名和实体类的类名一致 问题&#xff1a; 如果实体类类型的类名和要操作表的表名不一致会出现什么问题&#xff1f;(把 us…

Linux 压缩打包

Linux压缩打包 文章目录 Linux压缩打包压缩的意义和原理压缩的意义压缩的原理压缩与解压缩的好处 压缩打包命令.zipzip 命令用法unzip 的用法 .gzgzip 的用法gunzip 的用法 .bz2bzip2 的用法bunzip2 的用法 .xzxz 命令用法 tar 04-Linux压缩打包课后习题 压缩的意义和原理 压缩…

RabbitMQ深度探索:前置知识

消息中间件&#xff1a; 消息中间件基于队列模式实现异步 / 同步传输数据作用&#xff1a;可以实现支撑高并发、异步解耦、流量削峰、降低耦合 传统的 HTTP 请求存在的缺点&#xff1a; HTTP 请求基于响应的模型&#xff0c;在高并发的情况下&#xff0c;客户端发送大量的请求…

智慧校园平台:构建现代化教育体系的技术支撑

在当今信息技术飞速发展的时代&#xff0c;智慧校园平台成为了现代教育领域中的重要组成部分。智慧校园平台不仅能够提升学校的管理水平&#xff0c;还能提供更为个性化和高效的教学服务&#xff0c;从而促进学生的全面发展。 数据分析是智慧校园平台的重要组成部分。通过对学生…

20250204将Ubuntu22.04的默认Dash的shell脚本更换为bash

20250204将Ubuntu22.04的默认Dash的shell脚本更换为bash 2025/2/4 23:45 百度&#xff1a;dash bash https://blog.csdn.net/2201_75772333/article/details/136955776 【Linux基础】dash和bash简介 Dash&#xff08;Debian Almquist Shell&#xff09;和 Bash&#xff08;Bou…

Golang 并发机制-3:通道(channels)机制详解

并发编程是一种创建性能优化且响应迅速的软件的强大方法。Golang&#xff08;也称为 Go&#xff09;通过通道&#xff08;channels&#xff09;这一特性&#xff0c;能够可靠且优雅地实现并发通信。本文将揭示通道的概念&#xff0c;解释其在并发编程中的作用&#xff0c;并提供…

可视化大屏在石油方面的应用。

可视化大屏通过整合石油工业全链条数据&#xff0c;构建数字孪生驱动的运营监控体系&#xff0c;显著提升油气勘探、开采、储运及炼化的管理效能。其技术架构依托工业物联网&#xff08;IIoT&#xff09;实时采集钻井参数、管道压力、储罐液位等数据&#xff0c;通过OPC UA协议…

【学术投稿-2025年计算机视觉研究进展与应用国际学术会议 (ACVRA 2025)】从计算机基础到HTML开发:Web开发的第一步

会议官网&#xff1a;www.acvra.org 简介 2025年计算机视觉研究进展与应用&#xff08;ACVRA 2025&#xff09;将于2025年2月28-3月2日在中国广州召开&#xff0c;将汇聚世界各地的顶尖学者、研究人员和行业专家&#xff0c;聚焦计算机视觉领域的最新研究动态与应用成就。本次…

Axure PR 9 旋转效果 设计交互

大家好&#xff0c;我是大明同学。 这期内容&#xff0c;我们将学习Axure中的旋转效果设计与交互技巧。 旋转 创建旋转效果所需的元件 1.打开一个新的 RP 文件并在画布上打开 Page 1。 2.在元件库中拖出一个按钮元件。 创建交互 创建按钮交互状态 1.选中按钮元件&#xf…

Docker 部署教程jenkins

Docker 部署 jenkins 教程 Jenkins 官方网站 Jenkins 是一个开源的自动化服务器&#xff0c;主要用于持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;过程。它帮助开发人员自动化构建、测试和部署应用程序&#xff0c;显著提高软件开发的效率和质量…

计算图 Compute Graph 和自动求导 Autograd | PyTorch 深度学习实战

前一篇文章&#xff0c;Tensor 基本操作5 device 管理&#xff0c;使用 GPU 设备 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started PyTorch 计算图和 Autograd 微积分之于机器学习Computational Graphs 计算图Autograd…

接入DeepSeek大模型

接入DeepSeek 下载并安装Ollamachatbox 软件配置大模型 下载并安装Ollama 下载并安装Ollama&#xff0c; 使用参数ollama -v查看是否安装成功。 输入命令ollama list&#xff0c; 可以看到已经存在4个目录了。 输入命令ollama pull deepseek-r1:1.5b&#xff0c; 下载deepse…

【论文复现】粘菌算法在最优经济排放调度中的发展与应用

目录 1.摘要2.黏菌算法SMA原理3.改进策略4.结果展示5.参考文献6.代码获取 1.摘要 本文提出了一种改进粘菌算法&#xff08;ISMA&#xff09;&#xff0c;并将其应用于考虑阀点效应的单目标和双目标经济与排放调度&#xff08;EED&#xff09;问题。为提升传统粘菌算法&#xf…

UE Bridge混合材质工具

打开虚幻内置Bridge 随便点个材质点右下角图标 就能打开材质混合工具 可以用来做顶点绘制

基于 yolov8_pyqt5 自适应界面设计的火灾检测系统 demo:毕业设计参考

基于 yolov8_pyqt5 自适应界面设计的火灾检测系统 demo&#xff1a;毕业设计参考 【毕业设计参考】基于yolov8-pyqt5自适应界面设计的火灾检测系统demo.zip资源-CSDN文库 【毕业设计参考】基于yolov8-pyqt5自适应界面设计的火灾检测系统demo.zip资源-CSDN文库 一、项目背景 …