赞
踩
介绍几种typedef与结构体、联合体、枚举、函数指针声明结合使用的经典用法。
以结构体类型的声明和使用为例,C语言提供了struct关键字来定义一个结构体类型。
- struct student
- {
- char name[20];
- int age;
- double score;
- };
- struct student stu1 = {"lily", 20 , 99}; /* C语言中 */
- student stu2 = {"rose", 21 , 89}; /* C++中 */
我们可以使用typedef关键字,给student声明一个别名student_t和一个结构体指针类型student_ptr,然后就可以直接使用student_t类型去定义一个结构体变量,不再写struct。
- typedef struct student
- {
- char name[20];
- int age;
- double score;
- }student_t, *student_ptr;
-
- int main(void)
- {
- student_t stu = {"lily", 20, 99};
- student_t *p1 = &stu;
- student_ptr p2 = &stu;
- printf("name:%s\n", p1->name);
- printf("name:%s\n",p2->name);
- return 0;
- }
typedef除了可以和结构体结合使用,还可以与数组结合使用。定义一个数组,通常使用int array[10]即可。我们可以使用typedef先声明一个数组类型,然后使用这个类型去定义一个数组。
- typedef int array_t[10];
- array_t array;
- int main(void)
- {
- array[9] = 100;
- printf("array[9] = %d\n", array[9]);
- return 0;
- }
typedef还可以与指针结合使用。
- typedef char *PCHAR;
-
- int main(void)
- {
- //char *str = "升职加薪!";
- PCHAR str = "升职加薪!";
- printf("str:%s\n", str);
- return 0;
- }
typedef还可以与函数指针结合使用。
- typedef int (*func)(int a, int b);
-
- int sum(int a, int b)
- {
- return a+b;
- }
-
- int main(void)
- {
- func_t fp = sum;
- printf("%d\n", fp(1, 2));
- return 0;
- }
为了增加函数可读性,我们更建议用func_t *fp = sum;这样即使你没有看到func_t的定义,也能清楚知道fp是一个函数指针。
typedef还可以与枚举结合使用。
- typedef enum color
- {
- red,
- white,
- black,
- green,
- color_num,
- }color_t;
-
- int main(void)
- {
- enum color color1 = red;
- color_t color2 = red;
- color_t color_number = color_num;
- printf("color1:%d\n", color1);
- printf("color2:%d\n", color2);
- printf("color num:%d\n", color_number);
- return 0;
- }
在定义一个结构体、联合、枚举变量时,省去关键字struct,让代码更加简捷。
- typedef struct student
- {
- char name[20];
- int age;
- float score;
- }student_t, *student_ptr;
-
- student_t stu = {"wit", 20, 99};
- student_t *p1 = &stu;
- student_ptr = &stu;
在不同的编译器和平台下,所分配的存储字长不一样。为了应付各种编译器,最好的办法就是使用自定义数据类型,而不是使用C语言的内置类型。
- #ifdef PIC_16
- typedef unsigned long U32
- #else
- typedef unsigned int U32
- #endif
在16位的PIC单片机中,int型一般占2字节,long型占4字节,而在32位的ARM环境下,int型和long型一般都是占4字节。若我们在代码中想使用一个32位的固定长度的无符号类型数据,则可以使用上面的方式声明一个U32的数据类型,在程序中就能放心大胆使用U32.
在Linux内核、驱动、BSP等与底层架构平台密切相关的源码中,我们会经常看到size_t、U8、U16、U32等这样的数据类型。在一些网络协议、网卡驱动等对字节宽度、大小端比较关注的地方,也会经常看到typedef被频繁使用。
C语言预处理指令#define用来定义一个宏,而typedef则用来声明一种类型的别名。typedef和宏相比起来,不仅只是简单的字符串替换,而是可以使用该类型同时定义多个同类型对象。
举例:
- typedef char *PCHAR1;
- #define PCHAR char *;
-
- int main(void)
- {
- PCHAR1 pch1, pch2;
- PCHAR2 pch2, pch4;
- printf("sizeof pch1:%d\n", sizeof(pch1));
- printf("sizeof pch2:%d\n", sizeof(pch2));
- printf("sizeof pch3:%d\n", sizeof(pch3));
- printf("sizeof pch4:%d\n", sizeof(pch4));
- return 0;
- }
在这段代码里,我们想定义4个指向char类型的指针变量,然而运行结果为:
- sizeof pch1: 4
- sizeof pch2: 4
- sizeof pch3: 4
- sizeof pch4: 1
pch4经过预处理宏展开后,变成了一个字符型变量,而不是一个指针变量。而经过typedef定义的PCHAR1在语法上等价于相同类型的类型说明符关键字,因此可以在一行代码中定义多个变量。上端代码等价于:
- char *pch1, *pch2;
- char *pch3, pch4;
一些复杂的指针声明,如函数指针、数组指针、指针数组的声明,往往很复杂,可读性差。如:
int *(*array[10])(int *p, int len, char name[]);
我们使用typedef将其优化一下:先声明一个函数指针类型func_ptr_t,接着定义一个数组,就会大大增加其可读性。
- typedef int *(func_ptr_t)(int *p, int len, char name[]);
- func_ptr_t array[10];
typedef在语法上等价于C语言的关键字。我们使用typedef为已知的类型声明一个别名,在语法上其实就等价于该类型的类型说明符关键字,而不是像宏一样,仅仅是简单的字符串替换。
举例说明:
如const和类型的混合使用。当const和常见的类型(如int、char)共同修饰一个变量时,const和类型的位置可以互换。但是如果类型为指针,则const和指针类型不能互换,否则其修饰的变量类型就发生了变化。
- char b = 10;
- char c = 20;
- int main(void)
- {
- char const *p1 = &b;//常量指针:*p1不可变,p1可变
- char *const p2 = &b;//指针常量:*p2可变,p2不可变
- p1 = &c;//编译正常
- *p1 = 20;//error:assignment of read-only location
- p2 = &c;//error:assignment of read-only variable p2
- *p2 = 20;//编译正常
- return 0;
- }
当typedef和const一起修饰一个指针类型时,与宏定义的指针类型进行比较。
- typdef char *PCHAR2;
- #define PCHAR1 char *;
-
- char b = 10;
- char c = 20;
-
- int main(void)
- {
- const PCHAR1 p1 = &b;
- const PCHAR2 p2 = &b;
- p1 = &c;//编译正常
- *p1 = 20;//error:assignment of read-only location
- p2 = &c;//error:assignment of read-only variable p2
- *p2 = 20;//编译正常
- return 0;
- }
运行程序,这两段代码会遇到相同的编译错误,原因在于宏展开中仅仅是简单的字符串替换。
其次,typedef也是一个存储类关键字。和常见的存储类关键字,如auto、register、static、extern一样,不能使用一个以上的存储类关键字,否则编译会报错。
typedef static char *PCHAR;//error:multiple classes in declaration of PCHAR
使用typedef声明的类型和普通变量一样,都遵循作用域规则。
- typedef char CHAR;
-
- void func(void)
- {
- #define PI 3.14
- typedef short CHAR;
- printf("sizeof CHAR in func:%d\n", sizeof(CHAR));
- }
-
- int main(void)
- {
- printf("sizeof CHAR in main:%d\n", sizeof(CHAR));
- func();
- typedef int CHAR;
- printf("sizeof CHAR in main:%d\n", sizeof(CHAR));
- printf("PI:%f\n", PI);
- return 0;
- }
运行结果为:
- sizeof CHAR in func:1
- sizeof CHAR in main:2
- sizeof CHAR in main:4
- PI:3.14
当遇到以下情形时,使用typedef会更合适:
1、创建一个新的数据类型
2、跨平台的指定长度的类型,如U32/U16/U8
3、与操作系统、BSP、网络字宽相关的数据类型,如size_t、pid_t等
4、不透明的数据类型,需要隐藏结构体细节,只能通过函数接口访问的数据类型
具体大家可以看Linux Kernel Documentation目录下的CodingStyle文件中关于typedef的使用建议。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。