21. C语言 `typedef`:类型重命名

news2025/1/21 16:29:22

本章目录:

    • 前言
    • 1. 什么是 `typedef`?
      • 语法
      • 示例:基本类型的别名
    • 2. `typedef` 为结构体定义别名
      • 示例:为结构体定义别名
    • 3. `typedef` vs `#define`:两者的区别
      • (1) **作用范围和处理方式**
      • (2) **类型别名的处理**
      • (3) **多个变量的声明**
      • (4) **宏展开与编译器处理**
    • 4. `typedef` 的其他应用
      • (1) **为数组类型创建别名**
      • (2) **为复杂声明简化类型**
        • 示例:为函数指针类型创建别名
    • 5. 总结
      • 与 `#define` 的对比总结:


前言

在 C 语言中,typedef 是一个非常有用的关键字,它允许我们为现有的类型定义一个新的名字。这对于提高代码的可读性、简化复杂类型的声明以及减少错误非常有帮助。本文将详细探讨 typedef 的功能、使用场景以及与 #define 的区别,帮助你更好地理解和使用 typedef


1. 什么是 typedef

typedef 关键字用于为已有的类型(如基本数据类型、结构体、指针类型等)创建一个新的别名。它不会创建新的类型,只是为现有类型提供一个更具描述性的名字。typedef 主要用于提高代码的可读性和简化复杂的类型声明。

语法

typedef existing_type new_type_name;

在这个声明中,existing_type 是已存在的类型(可以是基本数据类型、结构体、指针等),而 new_type_name 是你想为这个类型定义的新名字。

示例:基本类型的别名

#include <stdio.h>

typedef unsigned char BYTE;

int main() {
    BYTE b1, b2;
    b1 = 10;
    b2 = 20;
    printf("b1: %d, b2: %d\n", b1, b2);
    return 0;
}

在上面的示例中,BYTE 成为了 unsigned char 的别名。通过 typedef,我们为 unsigned char 类型创建了一个更简洁且更具语义的名字 BYTE,使得代码更具可读性。

2. typedef 为结构体定义别名

typedef 在结构体类型中使用得非常广泛,尤其是在处理复杂的结构体时,它能显著简化变量的声明。

示例:为结构体定义别名

#include <stdio.h>
#include <string.h>

typedef struct Books {
    char title[50];
    char author[50];
    char subject[100];
    int book_id;
} Book;

int main() {
    Book book;

    strcpy(book.title, "C 教程");
    strcpy(book.author, "Runoob");
    strcpy(book.subject, "编程语言");
    book.book_id = 12345;

    printf("书标题 : %s\n", book.title);
    printf("书作者 : %s\n", book.author);
    printf("书类目 : %s\n", book.subject);
    printf("书 ID : %d\n", book.book_id);

    return 0;
}

通过使用 typedef,我们为 struct Books 类型创建了一个新的类型名 Book,从而在后续的代码中直接使用 Book 来声明变量。这比每次都写 struct Books 要方便很多。

3. typedef vs #define:两者的区别

虽然 typedef#define 都能够为类型创建别名,但它们之间有显著的差异。了解这些差异将帮助我们在不同场景中做出更合适的选择。

(1) 作用范围和处理方式

  • typedef 由编译器在编译时解析,它是类型别名的声明,并且只能用于为现有类型定义别名。
  • #define 是预处理器指令,在编译前由预处理器进行文本替换,它不仅可以为类型定义别名,还能为常量、表达式等定义别名。

(2) 类型别名的处理

typedef 的类型别名会被编译器识别并进行适当的类型检查,而 #define 只是简单的文本替换。例如:

#define INTERGE int
unsigned INTERGE n;  // 没问题

typedef int INTERGE;
unsigned INTERGE n;  // 错误,不能在 INTERGE 前添加 unsigned

#define 中,INTERGE 被简单地替换为 int,因此在 unsigned INTERGE n 中,INTERGE 会被替换为 int,这会导致变量 n 被定义为 unsigned int 类型。而 typedef 在定义时是严格的,不能在类型别名前再添加修饰符。

(3) 多个变量的声明

当你使用 typedef 时,所有声明的变量都会是同一类型,而 #define 无法保证这一点。例如:

#define PTR_INT int *
PTR_INT p1, p2;  // 错误,p1 是指针,p2 不是

typedef int * PTR_INT;
PTR_INT p1, p2;  // 正确,p1 和 p2 都是指针类型

#define PTR_INT int * 会把 PTR_INT 替换为 int *,因此 p1 成为指向 int 的指针,但 p2 则不是指针类型。而使用 typedef 时,PTR_INT 会同时作用于 p1p2,使它们都成为指针类型。

(4) 宏展开与编译器处理

#define 是由预处理器进行宏展开处理,而 typedef 由编译器解析。预处理器在处理 #define 时不会进行类型检查,而 typedef 会。

#define BYTE unsigned char
BYTE b1, b2;  // 无法保证类型的正确性

typedef unsigned char BYTE;
BYTE b1, b2;  // 类型检查会进行,确保一致性

4. typedef 的其他应用

(1) 为数组类型创建别名

你还可以使用 typedef 为数组类型创建别名,从而简化数组的声明和使用。

typedef int A[6];  // 定义一个新类型 A,它表示一个长度为 6 的整型数组
A a, b;  // a 和 b 都是 int[6] 类型的数组

(2) 为复杂声明简化类型

在处理复杂的声明时,typedef 可以帮助我们简化类型声明,尤其是在函数指针的使用中。

示例:为函数指针类型创建别名
typedef int *(*pFun)(int, char*);  // 定义一个函数指针类型

pFun a[5];  // a 是一个包含 5 个函数指针的数组

在这个例子中,pFun 是一个指向函数的指针类型,它接受一个 int 和一个 char* 类型的参数,返回 int* 类型的指针。通过 typedef,我们将复杂的声明变得更容易理解和使用。


5. 总结

typedef 是 C 语言中一个非常强大的工具,它可以让我们为类型创建别名,从而使代码更加简洁、可读性更强,并且有助于减少错误。相比于 #definetypedef 提供了更多的类型安全性和灵活性。在处理复杂类型、结构体、数组以及函数指针等时,typedef 是一个非常有用的工具。

#define 的对比总结:

  • 作用范围typedef 仅用于类型别名,#define 可用于类型、常量等的替换。
  • 类型检查typedef 由编译器处理,具备类型检查;#define 仅为文本替换,不做类型检查。
  • 代码简化typedef 在多变量声明中确保一致性,#define 则无法做到这一点。

掌握 typedef 的用法,将使你的 C 语言编程更为高效、简洁,并且能够在团队协作中提升代码的可读性和可维护性。


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

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

相关文章

软件测试—— 接口测试(HTTP和HTTPS)

软件测试—— 接口测试&#xff08;HTTP和HTTPS&#xff09; HTTP请求方法GET特点使用场景URL结构URL组成部分URL编码总结 POST特点使用场景请求结构示例 请求标头和响应标头请求标头&#xff08;Request Headers&#xff09;示例请求标头 响应标头&#xff08;Response Header…

OpenCV相机标定与3D重建(60)用于立体校正的函数stereoRectify()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 为已校准的立体相机的每个头计算校正变换。 cv::stereoRectify 是 OpenCV 中用于立体校正的函数&#xff0c;它基于已知的相机参数和相对位置&am…

ARP 表、MAC 表、路由表、跨网段 ARP

文章目录 一、ARP 表1、PC2、路由器 - AR22203、交换机 - S57004、什么样的设备会有 ARP 表&#xff1f; 二、MAC 表什么样的设备会有 MAC 表&#xff1f; 三、路由表什么样的设备会有路由表&#xff1f; 四、抓取跨网段 ARP 包 所谓 “透明” 就是指不用做任何配置 一、ARP 表…

深度学习 · 手撕 DeepLearning4J ,用Java实现手写数字识别 (附UI效果展示)

引言 随着人工智能技术的不断发展&#xff0c;手写数字识别已经成为深度学习领域的一个经典案例。不管是老牌的机器学习模型还是现代的神经网络架构&#xff0c;手写数字识别总是大家学习和实战的起点之一。而对于我们日常使用的Java开发者来说&#xff0c;借助DeepLearning4J…

天机学堂5-XxlJobRedis

文章目录 梳理前面的实现&#xff1a;Feign点赞改进 day07-积分系统bitmap相关命令签到增加签到记录计算本月已连续签到的天数查询签到记录 积分表设计签到-->发送RabbitMQ消息&#xff0c;保存积分对应的消费者&#xff1a;**消费消息 用于保存积分**增加积分查询个人今日积…

2024 年度学习总结

目录 1. 前言 2. csdn 对于我的意义 3. 写博客的初衷 3.1 现在的想法 4. 写博客的意义 5. 关于生活和博客创作 5.1 写博客较于纸质笔记的优势 6. 致 2025 1. 前言 不知不觉, 来到 csdn 已经快一年了, 在这一年中, 我通过 csdn 学习到了很多知识, 结识了很多的良师益友…

使用Chrome和Selenium实现对Superset等私域网站的截图

最近遇到了一个问题&#xff0c;因为一些原因&#xff0c;我搭建的一个 Superset 的 Report 功能由于节假日期间不好控制邮件的发送&#xff0c;所以急需一个方案来替换掉 Superset 的 Report 功能 首先我们需要 Chrome 浏览器和 Chrome Driver&#xff0c;这是执行数据抓取的…

[操作系统] 进程的调度

进程切换概念 时间⽚&#xff1a;当代计算机都是分时操作系统&#xff0c;没有进程都有它合适的时间⽚(其实就是⼀个计数 器)。时间⽚到达&#xff0c;进程就被操作系统从CPU中剥离下来。 死循环是如何运行&#xff1f; 当一个进程代码为死循环&#xff0c;它并不会一直占据C…

Biotin sulfo-N-hydroxysuccinimide ester ;生物素磺基-N-羟基琥珀酰亚胺酯;生物素衍生物;190598-55-1

一、生物素及其衍生物的概述 生物素衍生物是指在生物素&#xff08;Vitamin H或B7&#xff09;分子基础上进行化学修饰得到的衍生化合物。这些衍生化合物在生物医学研究、临床诊断和药物开发等领域有着广泛的应用。 生物素&#xff08;Biotin&#xff09;是一种水溶性维生素&a…

Jenkins-Pipeline简述

一. 什么是Jenkins pipeline&#xff1a; pipeline在jenkins中是一套插件&#xff0c;主要功能在于&#xff0c;将原本独立运行于单个或者多个节点的任务连接起来&#xff0c;实现单个任务难以完成的复杂发布流程。Pipeline的实现方式是一套Groovy DSL&#xff0c;任何发布流程…

Linux系统下安装配置Nginx(保姆级教程)

目录 前言 安装配置Nginx 一.下载依赖 二.下载Nginx 1. 访问官网?&#xff0c;获取需要的Nginx版本 2. 将文件下载到Linux系统 3. 解压文件 4. 解压成功后&#xff0c;当前文件夹会出现一个nginx-1.26.1文件夹&#xff0c;进入到文件夹内 5. 配置nginx 6.?编译并安…

《Linux服务与安全管理》| 邮件服务器安装和配置

《Linux服务与安全管理》| 邮件服务器安装和配置 目录 《Linux服务与安全管理》| 邮件服务器安装和配置 1.在Server01上安装dns、postfix、dovecot和telnet&#xff0c;并启动 2&#xff0e;在Server01上配置DNS服务器&#xff0c;设置MX资源记录 3&#xff0e;在server1上…

WPS数据分析000001

目录 一、表格的新建、保存、协作和分享 新建 保存 协作 二、认识WPS表格界面 三、认识WPS表格选项卡 开始选项卡 插入选项卡 页面布局选项卡 公式选项卡 数据选项卡 审阅选项卡 视图选项卡 会员专享选项卡 一、表格的新建、保存、协作和分享 新建 ctrlN------…

2025年免费量化交易软件——PTrade(含开通攻略)

量化交易软件&#xff0c;为广大投资者提供了一个便捷、高效的投资工具。 本文重点为大家介绍一款2025年好用的免费量化交易软件&#xff1a;PTrade量化&#xff0c;并详解其功能、特点、开通方法等。 一、PTrade的概念 PTrade是恒生电子开发的一款交易终端软件&#xff0c;旨…

【数据结构篇】顺序表 超详细

目录 一.顺序表的定义 1.顺序表的概念及结构 1.1线性表 2.顺序表的分类 2.1静态顺序表 2.2动态顺序表 二.动态顺序表的实现 1.准备工作和注意事项 2.顺序表的基本接口&#xff1a; 2.0 创建一个顺序表 2.1 顺序表的初始化 2.2 顺序表的销毁 2.3 顺序表的打印 3.顺序…

mysql查缺补漏

auto increment&#xff1a;自增序列&#xff0c;在字段后作为约束使用 comment&#xff1a;备注信息&#xff0c;用于在创建字段后或创建表的语句最后. 数值类型&#xff1a; 字符串类型&#xff1a; 日期类型&#xff1a; desc table_name&#xff1a;查询表结构 sho…

C++ 面向对象(继承)

三、继承 3.1 继承的概念 基于一个已有的类 去重新定义一个新的类&#xff0c;这种方式我们叫做继承 关于继承的称呼 一个类B 继承来自 类 A 我们一般称呼 A类&#xff1a;父类 基类 B类: 子类 派生类 B继承自A A 派生了B 示例图的语法 class vehicle // 车类 {}class …

JAVA-IO模型的理解(BIO、NIO)

前言 &#xff08;本文是作者学习制作rpc框架时&#xff0c;一些自用的笔记&#xff0c;并不会完整详细的介绍某个模块&#xff0c;会写大概的流程及一些相关概念&#xff0c;供日后复习使用~&#xff09; IO模型 先理解基本的IO流程&#xff1a; 应用A把消息发送到 TCP发送缓…

【Spring】原型 Bean 被固定

问题描述 在定义 Bean 时&#xff0c;有时候我们会使用原型 Bean&#xff0c;例如定义如下&#xff1a; Service Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class ServiceImpl { }然后我们按照下面的方式去使用它&#xff1a; RestController public class Hello…

奉加微PHY6230兼容性:部分手机不兼容

从事嵌入式单片机的工作算是符合我个人兴趣爱好的,当面对一个新的芯片我即想把芯片尽快搞懂完成项目赚钱,也想着能够把自己遇到的坑和注意事项记录下来,即方便自己后面查阅也可以分享给大家,这是一种冲动,但是这个或许并不是原厂希望的,尽管这样有可能会牺牲一些时间也有哪天原…