今天给大家讲typedef,这个关键字在实际产品开发中,也是海量应用。
技术涉及知识点比较多,有些并不常用,我们以贴近实际为原则,让大家把学习时间都花在重点上。
1.typedef的概念
typedef 是 C 语言中的一个关键字,可以为基本数据类型、结构体、联合体、枚举等创建一个新的类型名,有助工程师编写更清晰、更易于维护的代码。
2.typedef的几种用法
2.1用于基本数据类型
// 使用typedef关键字定义一个新类型名uint8_t,它代表无符号的8位字符(即0到255的整数)
typedef unsigned char uint8_t;
// 使用typedef关键字定义一个新类型名uint16_t,它代表无符号的16位短整型(即0到65535的整数)
typedef unsigned short uint16_t;
// 使用typedef关键字定义一个新类型名uint32_t,它代表无符号的32位整型(即0到4294967295的整数)
typedef unsigned int uint32_t;
// 声明一个类型为uint8_t的变量a,可以存储8位无符号整数
uint8_t a;
// 声明一个类型为uint16_t的变量b,可以存储16位无符号整数
uint16_t b;
// 声明一个类型为uint32_t的变量c,可以存储32位无符号整数
uint32_t c;
这段代码用typedef给unsigned char、unsigned short 和 unsigned int分别创建了uint8_t、uint16_t、uint32_t别名。
这里使用typedef给数据类型创建别名有什么作用或优势?
①.提高代码可读性
通过使用 uint8_t、uint16_t 和 uint32_t 这样的类型名,比直接使用基本数据类型 unsigned char、unsigned short 和 unsigned int 更易于理解。
②跨平台兼容性
不同的编译器或平台可能对基本数据类型的大小有不同的定义(例如,某些编译器可能将 int 定义为 16 位或 64 位),如果将来换了编译器或平台,只需更改 typedef 的定义,而不必在代码库中搜索和替换每个变量定义,代码维护更加容易。
③定义变量时更加方便
不用每次都写 unsigned char、unsigned short 和 unsigned int。
2.2用于结构体
我们可以通过以下方式创建结构体。
struct USART_InitTypeDef
{
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits;
uint16_t USART_Parity;
uint16_t USART_Mode;
uint16_t USART_HardwareFlowControl;
};
//定义结构体变量
struct USART_InitTypeDef stu_usart;
不过这种方式,每次定义结构体变量都要加struct .....,比较麻烦。
所以,我们可以用typedef关键字给结构体创建一个别名。
typedef struct
{
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits;
uint16_t USART_Parity;
uint16_t USART_Mode;
uint16_t USART_HardwareFlowControl;
} USART_InitTypeDef;
//定义结构体变量
USART_InitTypeDef stu_usart;
使用typedef给结构体创建了别名USART_InitTypeDef,下次就可以直接使用USART_InitTypeDef去定义结构体变量,不用再写struct了,这样代码更加方便简洁。
这种方式,在STM32之类的库文件里,有海量的使用。
2.3用于枚举
typedef enum
{
GPIO_Mode_AIN = 0x0,
GPIO_Mode_IN_FLOATING = 0x04,
GPIO_Mode_IPD = 0x28,
GPIO_Mode_IPU = 0x48,
GPIO_Mode_Out_OD = 0x14,
GPIO_Mode_Out_PP = 0x10,
GPIO_Mode_AF_OD = 0x1C,
GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;
//定义枚举变量
GPIOMode_TypeDef GPIO_Mode;
这段代码定义了一个枚举类型,使用 typedef 关键字,这个枚举类型被赋予了一个别名GPIOMode_TypeDef,下次需要定义该枚举类型变量时,可直接使用GPIOMode_TypeDef xx,这样代码可读性更高,也简洁。
这种方式,在实际产品中,也是用的非常多嘀。
2.4用于函数指针
我们先来看看不用typedef的函数指针创建方法:
//代码示例1,不用typedef的函数指针
// 定义一个函数,形参为无符号字符类型,无返回值。
void KeyEventHandle1(unsigned char keys)
{
//功能实现
}
void KeyEventHandle2(unsigned char keys)
{
//功能实现
}
//定义了一个函数指针 KeyEvent_CallBack_t,并将KeyEventHandle函数的地址赋给它。
void (*KeyEvent_CallBack_t1)(unsigned char) = KeyEventHandle1;
void (*KeyEvent_CallBack_t2)(unsigned char) = KeyEventHandle2;
这种方式,如果需要重复去定义同样的函数指针,是比较麻烦的,每次定义函数指针变量都要写void (*函数指针变量名)(形参1)......
下面来看看用typedef创建函数指针。
//使用了typedef定义函数指针类型KeyEvent_CallBack_t
typedef void (*KeyEvent_CallBack_t)(unsigned char keys);
void KeyEventHandle1(unsigned char keys)
{
//功能实现
}
void KeyEventHandle2(unsigned char keys)
{
//功能实现
}
KeyEvent_CallBack_t KeyScanCBS1 = KeyEventHandle1;
KeyEvent_CallBack_t KeyScanCBS2 = KeyEventHandle2;
很明显,我们可以用KeyEvent_CallBack_t 这个函数指针类型,直接定义函数指针变量,这样比不用typedef的方式要方便简洁很多,特别是对于那些形参多的函数。
这种方式,我自己做产品时用的很多,我们无际项目特训营的项目3和6都有挺多这种应用。
以上,是我做产品接触最多的几种用法,还有其它的,比如typedef+数组,typedef+联合体,我个人用的比较少。
用法基本万变不离其宗,掌握这几种,看到其它的也基本能融会贯通。
3.typedef的优势总结
我们来总结下,typedef最主要的几点优势:
-
提高代码可读性:通过使用有意义的类型名,代码更易于理解。
-
简化复杂类型:对于结构体、枚举、函数指针等复杂类型,使用 typedef 可以简化变量定义。
-
易于修改:如果基本类型需要更改,只需更改 typedef 定义,而不必修改使用该类型的所有实例。
-
增加代码移植性:不同编译器或平台可能对某些数据类型的大小有差别(例如,int在某些平台上可能是16位,在另一些平台上可能是32位或64位)。通过使用 typedef,可以在不同的平台上定义相同的名字来代表具有适当大小和对齐的数据类型。
最近很多粉丝问我单片机怎么学,我根据自己从业十年经验,累积耗时一个月,精心整理一份「单
片机最佳学习路径+单片机入门到高级教程+工具包」,全部无偿分享给铁粉!!!
除此以外,再含泪分享我压箱底的22个热门开源项目,包含源码+原理图+PCB+说明文档,让你迅速进阶成高手!
教程资料包和详细的学习路径可以看我下面这篇文章的开头。
《单片机入门到高级开挂学习路径(附教程+工具)》
《单片机入门到高级开挂学习路径(附教程+工具)》
《单片机入门到高级开挂学习路径(附教程+工具)》