当前位置:   article > 正文

typedef几种经典用法

typedef

介绍几种typedef与结构体、联合体、枚举、函数指针声明结合使用的经典用法。

一、typedef的基本用法

以结构体类型的声明和使用为例,C语言提供了struct关键字来定义一个结构体类型。

  1. struct student
  2. {
  3. char name[20];
  4. int age;
  5. double score;
  6. };
  7. struct student stu1 = {"lily", 20 , 99}; /* C语言中 */
  8. student stu2 = {"rose", 21 , 89}; /* C++中 */

 我们可以使用typedef关键字,给student声明一个别名student_t和一个结构体指针类型student_ptr,然后就可以直接使用student_t类型去定义一个结构体变量,不再写struct。

  1. typedef struct student
  2. {
  3. char name[20];
  4. int age;
  5. double score;
  6. }student_t, *student_ptr;
  7. int main(void)
  8. {
  9. student_t stu = {"lily", 20, 99};
  10. student_t *p1 = &stu;
  11. student_ptr p2 = &stu;
  12. printf("name:%s\n", p1->name);
  13. printf("name:%s\n",p2->name);
  14. return 0;
  15. }

typedef除了可以和结构体结合使用,还可以与数组结合使用。定义一个数组,通常使用int array[10]即可。我们可以使用typedef先声明一个数组类型,然后使用这个类型去定义一个数组。

  1. typedef int array_t[10];
  2. array_t array;
  3. int main(void)
  4. {
  5. array[9] = 100;
  6. printf("array[9] = %d\n", array[9]);
  7. return 0;
  8. }

typedef还可以与指针结合使用。

  1. typedef char *PCHAR;
  2. int main(void)
  3. {
  4. //char *str = "升职加薪!";
  5. PCHAR str = "升职加薪!";
  6. printf("str:%s\n", str);
  7. return 0;
  8. }

typedef还可以与函数指针结合使用。

  1. typedef int (*func)(int a, int b);
  2. int sum(int a, int b)
  3. {
  4. return a+b;
  5. }
  6. int main(void)
  7. {
  8. func_t fp = sum;
  9. printf("%d\n", fp(1, 2));
  10. return 0;
  11. }

为了增加函数可读性,我们更建议用func_t *fp = sum;这样即使你没有看到func_t的定义,也能清楚知道fp是一个函数指针。

typedef还可以与枚举结合使用。

  1. typedef enum color
  2. {
  3. red,
  4. white,
  5. black,
  6. green,
  7. color_num,
  8. }color_t;
  9. int main(void)
  10. {
  11. enum color color1 = red;
  12. color_t color2 = red;
  13. color_t color_number = color_num;
  14. printf("color1:%d\n", color1);
  15. printf("color2:%d\n", color2);
  16. printf("color num:%d\n", color_number);
  17. return 0;
  18. }

二、typedef的优势

1、让代码更加清晰简洁

在定义一个结构体、联合、枚举变量时,省去关键字struct,让代码更加简捷。

  1. typedef struct student
  2. {
  3. char name[20];
  4. int age;
  5. float score;
  6. }student_t, *student_ptr;
  7. student_t stu = {"wit", 20, 99};
  8. student_t *p1 = &stu;
  9. student_ptr = &stu;

2、增加代码的可移植性

在不同的编译器和平台下,所分配的存储字长不一样。为了应付各种编译器,最好的办法就是使用自定义数据类型,而不是使用C语言的内置类型。

  1. #ifdef PIC_16
  2. typedef unsigned long U32
  3. #else
  4. typedef unsigned int U32
  5. #endif

在16位的PIC单片机中,int型一般占2字节,long型占4字节,而在32位的ARM环境下,int型和long型一般都是占4字节。若我们在代码中想使用一个32位的固定长度的无符号类型数据,则可以使用上面的方式声明一个U32的数据类型,在程序中就能放心大胆使用U32.

在Linux内核、驱动、BSP等与底层架构平台密切相关的源码中,我们会经常看到size_t、U8、U16、U32等这样的数据类型。在一些网络协议、网卡驱动等对字节宽度、大小端比较关注的地方,也会经常看到typedef被频繁使用。

3、比宏定义更好用

C语言预处理指令#define用来定义一个宏,而typedef则用来声明一种类型的别名。typedef和宏相比起来,不仅只是简单的字符串替换,而是可以使用该类型同时定义多个同类型对象。

举例:

  1. typedef char *PCHAR1;
  2. #define PCHAR char *;
  3. int main(void)
  4. {
  5. PCHAR1 pch1, pch2;
  6. PCHAR2 pch2, pch4;
  7. printf("sizeof pch1:%d\n", sizeof(pch1));
  8. printf("sizeof pch2:%d\n", sizeof(pch2));
  9. printf("sizeof pch3:%d\n", sizeof(pch3));
  10. printf("sizeof pch4:%d\n", sizeof(pch4));
  11. return 0;
  12. }

在这段代码里,我们想定义4个指向char类型的指针变量,然而运行结果为:

  1. sizeof pch1: 4
  2. sizeof pch2: 4
  3. sizeof pch3: 4
  4. sizeof pch4: 1

 pch4经过预处理宏展开后,变成了一个字符型变量,而不是一个指针变量。而经过typedef定义的PCHAR1在语法上等价于相同类型的类型说明符关键字,因此可以在一行代码中定义多个变量。上端代码等价于:

  1. char *pch1, *pch2;
  2. char *pch3, pch4;

4、让复杂的指针声明更加简洁

一些复杂的指针声明,如函数指针、数组指针、指针数组的声明,往往很复杂,可读性差。如:

int *(*array[10])(int *p, int len, char name[]);

我们使用typedef将其优化一下:先声明一个函数指针类型func_ptr_t,接着定义一个数组,就会大大增加其可读性。

  1. typedef int *(func_ptr_t)(int *p, int len, char name[]);
  2. func_ptr_t array[10];

三、使用typedef的注意事项

typedef在语法上等价于C语言的关键字。我们使用typedef为已知的类型声明一个别名,在语法上其实就等价于该类型的类型说明符关键字,而不是像宏一样,仅仅是简单的字符串替换。

举例说明:

如const和类型的混合使用。当const和常见的类型(如int、char)共同修饰一个变量时,const和类型的位置可以互换。但是如果类型为指针,则const和指针类型不能互换,否则其修饰的变量类型就发生了变化。

  1. char b = 10;
  2. char c = 20;
  3. int main(void)
  4. {
  5. char const *p1 = &b;//常量指针:*p1不可变,p1可变
  6. char *const p2 = &b;//指针常量:*p2可变,p2不可变
  7. p1 = &c;//编译正常
  8. *p1 = 20;//error:assignment of read-only location
  9. p2 = &c;//error:assignment of read-only variable p2
  10. *p2 = 20;//编译正常
  11. return 0;
  12. }

当typedef和const一起修饰一个指针类型时,与宏定义的指针类型进行比较。

  1. typdef char *PCHAR2;
  2. #define PCHAR1 char *;
  3. char b = 10;
  4. char c = 20;
  5. int main(void)
  6. {
  7. const PCHAR1 p1 = &b;
  8. const PCHAR2 p2 = &b;
  9. p1 = &c;//编译正常
  10. *p1 = 20;//error:assignment of read-only location
  11. p2 = &c;//error:assignment of read-only variable p2
  12. *p2 = 20;//编译正常
  13. return 0;
  14. }

运行程序,这两段代码会遇到相同的编译错误,原因在于宏展开中仅仅是简单的字符串替换。

其次,typedef也是一个存储类关键字。和常见的存储类关键字,如auto、register、static、extern一样,不能使用一个以上的存储类关键字,否则编译会报错。

typedef static char *PCHAR;//error:multiple classes in declaration of PCHAR

四、typedef的作用域

使用typedef声明的类型和普通变量一样,都遵循作用域规则。

  1. typedef char CHAR;
  2. void func(void)
  3. {
  4. #define PI 3.14
  5. typedef short CHAR;
  6. printf("sizeof CHAR in func:%d\n", sizeof(CHAR));
  7. }
  8. int main(void)
  9. {
  10. printf("sizeof CHAR in main:%d\n", sizeof(CHAR));
  11. func();
  12. typedef int CHAR;
  13. printf("sizeof CHAR in main:%d\n", sizeof(CHAR));
  14. printf("PI:%f\n", PI);
  15. return 0;
  16. }

运行结果为:

  1. sizeof CHAR in func:1
  2. sizeof CHAR in main:2
  3. sizeof CHAR in main:4
  4. PI:3.14

五、总结

当遇到以下情形时,使用typedef会更合适:

1、创建一个新的数据类型

2、跨平台的指定长度的类型,如U32/U16/U8

3、与操作系统、BSP、网络字宽相关的数据类型,如size_t、pid_t等

4、不透明的数据类型,需要隐藏结构体细节,只能通过函数接口访问的数据类型

具体大家可以看Linux Kernel Documentation目录下的CodingStyle文件中关于typedef的使用建议。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/483436
推荐阅读
相关标签
  

闽ICP备14008679号