数据类型起别名( typedef )
1 回顾定义定义的数据类型
// 基本的数据类型
int m_i;
unsigned int m_ui;
// 数组
short m_arr1[2];
unsigned int m_arr2[2][2];
// 指针
int *p;
int **pp;
// 指针数组/数组指针
int *p_arr[2];
int (*arr_p)[2];
// 函数指针
int (*func_p)(int, int);
// 函数指针数组
int (*func_p_arr[2])(int, int);
2 定义变量的数据类型
将变量名去除,剩余的就是你定义变量的数据类型
// 基本的数据类型
int ;
unsigned int ;
// 数组
short [2];
unsigned int [2][2];
// 指针
int *;
int **;
// 指针数组/数组指针
int *[2];
int (*)[2];
// 函数指针
int (*)(int, int);
// 函数指针数组
int (*[2])(int, int);
3 使用新的数据类型定义变量
将typedef写到定义变量的前边,此时变量名就是你的新定义的数据类型,可以使用新的数据类型定义变量
将typedef写到定义变量的前边,此时变量名就是你的新定义的数据类型,可以使用新的数据类型定义变量,
// 基本的数据类型
typedef int myint32_t; // myint32_t是使用typedef对int类型起别名
typedef unsigned int myuint32_t; // myuint32_t是使用typedef对unsigned int类型起别名
// 数组
typedef short m_arr1_t[2]; // m_arr1_t是使用typedef对short [2]类型起别名
typedef unsigned int m_arr2_t[2][2]; // m_arr12_t是使用typedef对unsigned int [2][2]类型起别名
// 指针
typedef int *p_t; // p_t是使用typedef对int *类型起别名
typedef int **pp_t;// pp_t是使用typedef对int **类型起别名
// 指针数组/数组指针
typedef int *p_arr_t[2]; // p_arr_t是使用typedef对int *[2]类型起别名
typedef int (*arr_p_t)[2]; // arr_p_t是使用typedef对int (*)[2]类型起别名
// 函数指针
typedef int (*func_p_t)(int, int); // func_p_t是使用typedef对int (*)(int, int)类型起别名
// 函数指针数组
typedef int (*func_p_arr_t[2])(int, int);
// func_p_arr_t是使用typedef对int (*[2])(int, int)类型起别名
使用tppedef对数据类型起别名之后,使用别名定义变量和使用本身代表的类型定义变量一样一样。
4 参考案例
#include <stdio.h>
// 使用typedef对数据类型起别名
// 基本的数据类型
typedef int myint32_t; // myint32_t是使用typedef对int类型起别名
typedef unsigned int myuint32_t; // myuint32_t是使用typedef对unsigned int类型起别名
// 数组
typedef short m_arr1_t[2]; // m_arr1_t是使用typedef对short [2]类型起别名
typedef unsigned int m_arr2_t[2][2]; // m_arr12_t是使用typedef对unsigned int [2][2]类型起别名
// 指针
typedef int *p_t; // p_t是使用typedef对int *类型起别名
typedef int **pp_t; // pp_t是使用typedef对int **类型起别名
// 指针数组/数组指针
typedef int *p_arr_t[2]; // p_arr_t是使用typedef对int *[2]类型起别名
typedef int (*arr_p_t)[2]; // arr_p_t是使用typedef对int (*)[2]类型起别名
// 函数指针
typedef int (*func_p_t)(int, int); // func_p_t是使用typedef对int (*)(int, int)类型起别名
// 函数指针数组
typedef int (*func_p_arr_t[2])(int, int);
// func_p_arr_t是使用typedef对int (*[2])(int, int)类型起别名
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int main(int argc, const char *argv[])
{
/*your code*/
// 基本类型 ----> 比较常见
myint32_t a = 1000; // 等价于 int a = 1000;
// 数组 ---> 基本不用
m_arr1_t arr1 = {100, 200}; // 等价于short arr1[2]={100,200};
m_arr2_t arr2 = {{100, 200}, {300, 400}};
// 等价于 unsigned int arr2[2][2] = {{100,200},{300,400}};
// 指针 ----> 基本不用
p_t p = &a; // 等价于int *p = &a;
pp_t pp = &p; // 等价于 int **p = &p;
// 指针数组/数组指针 ----> 偶尔使用
p_arr_t p_arr = {&a, &a}; // 等价于 int *p_arr[2] = {&a, &a};
int arr[2][2] = {{100, 200}, {300, 400}};
arr_p_t arr_p = arr; // 等价于 int (*arr_p)[2] = arr;
// 函数指针 ----> 经常使用
func_p_t cal_p = add; // 等价于 add;int (*cal_p)(int, int) =
/*
int calculator(int x, int y, int (*cal_p)(int,int))
{
return cal_p(x,y);
}
使用函数指针类型的别名:
int calculator(int x, int y, func_p_t cal_p)
{
return cal_p(x,y);
}
*/
func_p_arr_t func_p_arr = {add,sub};
// 等价于int (*func_p_arr[2])(int, int) = {add,sub};
return 0;
}
5 typedef和#define的区别
#define宏定义对数据类型起别名在预处理阶段展开;
typedef对数据类型起别名参与到了编译的阶段;使用typedef对数据类型起别名相当于重新定义了一个新的数据类型;
宏定义就是在预处理阶段进行替换。推荐使用typedef对数据类型起别名定义新的数据类型。
#define p_t int * p_t p, q; // int *p, q; // p是int*类型,q是int类型。 typedef int *p_t; p_t p, q; // int *p, *q; // p和q都是int*类型
宏定义的结尾不允许出现分号,typedef的结尾必须加分号。
6 typedef的陷阱
陷阱一:
记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如先定义:
typedef char* PSTR;
然后:
int mystrcmp(const PSTR, const PSTR);
const PSTR实际上相当于const char*吗?
不是的,它实际上相当于char* const。
原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const。
简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。
陷阱二:
typedef在语法上是一个存储类的关键字(如auto、extern、static、register等一样),虽然它并不真正影响对象的存储特性,如:
typedef static int INT2; //不可行
编译将失败,会提示“指定了一个以上的存储类”。