C语言学习及应用笔记之五:C语言typedef关键字及其使用
在C语言中有一个typedef关键字,其用来定义用户自定义类型。当然,并不是真的创造了一种数据类型,而是给已有的或者符合型的以及复杂的数据类型取一个我们自己更容易理解的别名。总之,可以使用typedef关键字定义一个我们自己的类型名称。
那么,究竟如何定义,又有哪些情况下可已使用呢?接下来我们就对它的几种用法进行说明:
(1)基本数据类型定义
有些时候,我们会使用typedef关键字对一些基本数据类型进行重新定义。例如我们使用标准整数的数据类型uint8_t和uint16_t等时,其实他们的定义如下:
typedef unsigned char uint8_t; //无符号8位数
typedef signed char int8_t; //有符号8位数
typedef unsigned int uint16_t; //无符号16位数
typedef signed int int16_t; //有符号16位数
typedef unsigned long uint32_t; //无符号32位数
typedef signed long int32_t; //有符号32位数
很显然就是使用了typedef关键字给既有数据类型分配了一个别名。当我们使用uint8_t时,就和使用unsigned char是一样的。如我们声明uint8_t var时,和使用unsigned char var是一回事。
(2)指针数据类型定义
有些时候我们也会使用typedef关键字定义指针数据类型,用以简化我们所使用的指针变量的声明。
例如:typedef int *pointer;
这样我们就定义了一个指针类型,当我们使用pointer p声明一个指针变量,就和使用int *p的含义是一样的。
上面是一个指针变量类型,可以演化出很多用法,如定义数组对象可以更明确。有时候,我们也定义指向二位数组行的指针,使用typedef关键字就可以使得操作更符合我们的常规认知。
例如: typedef int (*pointer)[N];
这里pointer等价于 int (*)[N],当我们声明pointer p就相当于声明int (*a)[N]。同样的,如果我们对二维数组采用类似的定义。
例如:typedef int array[M][N];
那它的含义与指针是类似的,如我们定义array a就是声明了一个M行N列的数组,此时使用p=a是可以的。
我们考虑到数组很多时候可以使用指针表示,所以将其放在一起讨论,而其它一些对象指针我们单独讨论。其实,不光是上述数组和指针可以使用typedef关键字定义别名,其它如:一维和多位数组,指针数组等都可以这样使用。
(3)用户对象类型定义
首先说明,这里说所的用户对象是指结构体、联合体以及枚举等用户定义的数据类型。我们可以使用typedef关键字给结构体等类型定义一个别名,这样我们客气在多个地方更方便的使用它。当然很多人对此有不同看法,这里不讨论,我们只是说有这种用法。
使用typedef关键字为结构体类型定义一个别名。
例如:typedef struct{
float setpoint; /*设定值*/
float kp; /*比例系数*/
float ki; /*积分系数*/
float kd; /*微分系数*/
float lasterror; /*前一拍偏差*/
float preerror; /*前两拍偏差*/
float deadband; /*死区*/
float result; /*PID控制器计算结果*/
float output; /*输出值0-100%*/
float maximum; /*输出值上限*/
float minimum; /*输出值下限*/
float errorabsmax; /*偏差绝对值最大值*/
float errorabsmin; /*偏差绝对值最小值*/
float alpha; /*不完全微分系数*/
float deltadiff; /*微分增量*/
float integralValue; /*积分累计量*/
float gama; /*微分先行滤波系数*/
float lastPv; /*上一拍的过程测量值*/
float lastDeltaPv; /*上一拍的过程测量值增量*/
}CLASSICPID;
这样我们在需要使用结构体类型定义一个对象时,我们可以使用CLASSICPID vPID就可以了与使用原始定义是一样的。
同样我们也可以使用typedef关键字为枚举类型定义一个别名。
例如:typedef enum {
FC_REG_Write=((uint8_t)0x80), /*写寄存器的功能码*/
FC_REG_Read=((uint8_t)0x81), /*读寄存器的功能码*/
FC_VAR_Write=((uint8_t)0x82), /*写变量的功能码*/
FC_VAR_Read=((uint8_t)0x83), /*读变量的功能码*/
FC_Curve_Write=((uint8_t)0x84) /*写曲线缓冲区的功能码*/
}DwinFunctionCode;
我们需要定义枚举变量时,也是使用DwinFunctionCode fc就可以了。当然,我们也可已使用定义的类型声明指针变量,或者直接使用typedef关键字定义指向对象的指针类型,如定义结构体指针类型。
(4)函数类型定义
typedef关键字也常用来定义函数类型,用以声明同类型的函数或者函数指针变量。这一种类型定义在函数用作形参等一回调的方式使用时,非常有用,具体用法可参考回调函数的使用。
使用typedef关键字定义函数类型与前面的各种定义方式类式。
例如: typedef int fType(void);
在这里fType等价于 int (void)类型函数。如果我们使用fType function声明函数function时,与使用int function (void)来声明是一样的。
同样我们也可以使用fType来定义函数指针。如果我们使用fType *fPointer声明函数指针fPointer时,和使用int (*fPointer) (void)来声明是一样的。
当然,我们也可以使用typedef关键字直接定义函数指针类型。
例如: typedef int (*fPointer)(void);
这样我们就可以使用fPointer来定义一个函数指针。如我们使用fPointer fp声明函数指针就如同使用int (*fp)(void)来声明。
(5)typedef关键字与宏定义
我们已经说明了typedef关键字的基本用法。但我们发现它的功能视乎宏定义也能实现,所以我们接下来说明一下typedef关键字和#define定义的宏之间究竟有何不同。
从功能范围上讲是有区别的,typedef主要是为已存在的关键字或类型及其组合取一个我们容易识别的别名。在这一点上#define也可实现,但初次之外#define还有很多其它用处,如果愿意你可以使用它定义任何代码,这时typedef所不具备的。
执行时间也是有区别的,对于#define定义的宏,其在预处理阶段就会被替换。而typedef定义的类型会在编译时处理。
从作用于上来讲也是有区别的,一般来说#define定义的宏没有作用于的限制,只要在使用前有定义就可以了。而typedef定义的别名是有作用于的。
从实现效果来讲也是有区别的,我们使用typedef定义一个指针类型,然后使用该类型可以同时声明对各变量,而#define却不是这样的。如typedef (int*) pType;可以使用pType a,b;这里a和b都是指向整数的指针变量。但我们同样定义#define pType int*,若使用pType a,b;定义a和b,则a是指向整数的指针变量,而b不是。
欢迎关注:
如果阅读这篇文章让您略有所得,还请点击下方的【好文要顶】按钮。
当然,如果您想及时了解我的博客更新,不妨点击下方的【关注我】按钮。
如果您希望更方便且及时的阅读相关文章,也可以扫描上方二维码关注我的微信公众号【木南创智】