本文研究C语言中typedef关键字的作用。
1 typedef关键字的作用
本科学过C语言的朋友都知道数据类型的概念。C语言中有整型,如char、int、short等等;也有浮点类型,如float、double。
typedef关键字就是给这些数据类型起一个别的名字,然后用这个自己起的名字来定义变量。比如如下语句就把char类型起了个新的名字叫int8。然后用int8定义了一个变量a1。
typedef char int8;
int8 a1;
那么为什么不能直接用基础类型来定义变量,本文就研究其中的原因。
2 typedef关键字的场景
2.1 重新定义基本类型
Simulink生成的代码中,在rtwtypes.h头文件中专门有一组typedef,它们把一些基本类型,如char、float等,定义成别的名字。
然后定义变量的时候不去用基础类型定义,而是用int8_T,real32_T这些自己起名的类型去定义变量。
以前博主对此很费解,为啥要没事找事转一道。后来接触到MISRA-C规范后,才明白里面的意义。MISRA-C 2004规范的6.3条中说到,应该使用指示了大小和符号的typedef以代替基本数据类型。
所以,把unsigned char用typedef转换成uint8_T的话,后面定义变量的时候就可以很清楚的知道这个变量是uint8的,范围是0~255。
另外,32位系统和64位系统中,基础类型对应的字节长度可能不同。如果整个工程中的代码全都是基础类型,再移植代码到新系统的时候可能要全部改一遍。而如果用了typedef,只需要改一下typedef这一句就行了。
2.2 为变量定义专属类型
首先思考一个场景。一个C语言工程中有很多函数,他们都需要传参数ObjNum,输入雷达检测到的目标个数。由于在函数定义的时候需要明确传递参数的数据类型,所以这些函数就定义成这样:
void function_1(uint8 ObjNum);
void function_2(uint8 ObjNum);
void function_3(uint8 ObjNum);
uint8最大可以表示255,如果想把ObjNum改成uint16类型的,就需要改3次(在大的工程中不止3个),所以一个好的办法就是用typedef,给这个变量定义一个专属的类型名称,如下:
typedef uint8 ObjNumType;
void function_1(ObjNumType ObjNum);
void function_2(ObjNumType ObjNum);
void function_3(ObjNumType ObjNum);
这样,只需要在typedef把uint8改成uint16就可以。
2.3 定义结构体、枚举量、数组
结构体由程序员自己定义,通常是把一些有着共同特征的变量打包在一起,以便增强可读性。例如,汽车动力学相关的变量就包括车速、横摆角速度、加速踏板等,可以把他们打包到一起定义一个结构体类型:
typedef struct VehicleDynamics_Tag
{
float32 VehicleSpeed;
float32 Yawrate;
bool AccelerationPedal;
} VehicleDynamics_Type;
然后再用结构体类型定义一个结构体变量:
VehicleDynamics_Type vehicle_dynamics;
另外,枚举量的定义也类似,譬如定义LKA功能状态:
typedef enum LKAStatus_Tag
{
LKA_OFF= 0,
LKA_STANDBY,
LKA_ACTIVE,
LKA_OVERRIDE
} LKAStatus_Type;
对于数组定义,可以看一个例子。
#include <iostream>
typedef unsigned char ObjID[10];
int main()
{
ObjID id;
for (int i = 0; i < 10; i++)
{
id[i] = i;
}
printf("id[4] = %d\r\n", id[4]);
printf("id = %p\r\n", id);
}
用typedef定义一个无符号整型的数组类型ObjID[10],这表明类型是ObjID,数组size是10。在主函数中再通过ObjID定义id,注意这里的id变量指的是数组的首地址。再通过下标就可以访问数组元素,例如id[4]。
打印数组元素和数组地址如下图:
3 总结
目前博主工作中遇到的typedef主要就是以上3种非常常见的情况。