C/C++ typedef用法详解

一、typedef简介

typedef的4种常见用法

1、给已定义的变量类型起个别名
2、定义函数指针类型
3、定义数组指针类型
4、为复杂的声明定义一个新的简单的别名

总结一句话:“加不加typedef,类型是一样的“,这句话可以这样理解:
没加typedef之前如果是个数组,那么加typedef之后就是数组类型;
没加typedef之前如果是个函数指针,那么加typedef之后就是函数指针类型;
没加typedef之前如果是个指针数组,那么加typedef之后就是指针数组类型;

typedef char TA[5];//定义数组类型
typedef char *TB[5];//定义指针数组类型,PA定义的变量为含5个char*指针元素的数组(指针数组类型)
typedef char *(TC[5]);//指针数组类型,因为[]的结合优先级最高,所以加不加()没啥区别,TC等价于TB
typedef char (*TD)[5];//数组指针类型

二、typedef的4种用法详解

1、给已定义的变量类型起个别名

(1)typedef unsigned char uin8_t; //uint8_t就是unsigned char的别名,这是最基础的用法
(2)结构体用法——作用是给struct __person起了个别名person_t,这种这种用法也很基础

struct __person
{
    char    name[20];
    uint8_t age;
    uint8_t height;
}
typedef __person person_t;
//以上两段代码也可合并为一段,如下:
typedef struct __person
{
    char    name[20];
    uint8_t age;
    uint8_t height;
}person_t;

2、定义函数指针类型

首先来看一下如何定义函数指针变量,然后再看如何定义函数指针类型
(1)定义函数指针变量

int (*pFunc)(char *frame, int len);

定义了一个函数指针变量pFunc,它可以指向这样的函数:返回值为int,形参为char*、int

int *(*pFunc[5])(int len);

定义了5个函数指针变量:pFunc[0]、pFunc[1]···,它们都可以指向这样的函数:返回值为int*,形参为int
(2)定义函数指针类型
定义函数指针类型,必须使用typedef,方法就是,在“定义函数指针变量”加上typedef。
typedef int (*pFunc_t)(char *frame, int len);//定义了一个类型pFunc_t
举例:

typedef  int (*pFunc_t)(char *frame, int len);//定义了一个类型pFunc_t
int read_voltage(char *data, int len)
{
    int voltage = 0;
    ···//其他功能代码
    return voltage;
}
int main(void)
{
    pFunc_t   pHandler = read_voltage;//使用类型pFunc_t来定义函数指针变量
    ···//其他功能代码
}

3、定义数组指针类型

这个问题还是分两步,先看如何定义数组指针变量,再看如何定义数组指针类型
(1)定义数组指针变量

① int(*pArr)[5];//定义了一个数组指针变量pArr,pArr可以指向一个int [5]的一维数组
② char(*pArr)[4][5];///定义了一个数组指针变量pArr,pArr可以指向一个char[4][5]的二维数组

int(*pArr)[5];//pArr是一个指向含5个int元素的一维数组的指针变量
int a[5] = {1,2,3,4,5};
int b[6] = {1,2,3,4,5,6};
pArr = &a;//完全合法,无警告
pArr = a;//发生编译警告,赋值时类型不匹配:a的类型为int(*),而pArr的类型为int(*)[5]
pArr = &a[0];//发生编译警告,赋值时类型不匹配:a的类型为int(*),而pArr的类型为int(*)[5]
pArr = &b;//发生编译警告,赋值时类型不匹配:&b的类型为int(*)[6],而pArr的类型为int(*)[5]
pArr = (int(*)[5])&b;//类型强制转换为int(*)[5],完全合法,无警告

上面这个例子中,使用类型转换时,代码的样式略显复杂,试想,我们如果强转为一个结构体数组的指针,那这个强转的括号里的内容得多长!这就直接影响了代码的可读性,因此,强转后的类型应该定义出来

(2)定义数组指针类型
如同上面定义函数指针类型的方法,直接在前面加typedef即可,例如
typedef int (*pArr_t)[5];//定义了一个指针类型pArr_t,该类型的指针可以指向含5个int元素的数组

typedef int(*pArr_t)[5];//定义一个指针类型,该类型的指针可以指向含5个int元素的一维数组
 
int main(void)
{
    int a[5] = {1,2,3,4,5};
    int b[6] = {1,2,3,4,5,6};
    pArr_t pA;//定义数组指针变量pA
    pA= &a;//完全合法,无警告    
    pA= (pArr_t)&b;//类型强制转换为pArr_t,完全合法,无警告
}

(2)定义数组类型
如果我们想声明一个含5个int元素的一维数组,一般会这么写:int a[5];
如果我们想声明多个含5个int元素的一维数组,一般会这么写:int a1[5], a2[5], a3[5]···,或者 a[N][5]
可见,对于定义多个一维数组,写起来略显复杂,这时,我们就应该把数组定义为一个类型,例如:
typedef int arr_t[5];//定义了一个数组类型arr_t,该类型的变量是个数组

typedef int arr_t[5];
int main(void)
{
    arr_t d;        //d是个数组,这一行等价于:  int d[5];
    arr_t b1, b2, b3;//b1, b2, b3都是数组
    
    d[0] = 1;
    d[1] = 2;
    d[4] = 134;
    d[5] = 253;//编译警告:下标越界
}

4、为复杂的声明定义一个新的简单的别名

为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例:

int *(*a[5])(int, char*);//原声明

typedef int *(*pFun)(int, char*); //变量名为a,直接用一个新别名pFun替换a就可以了
pFun a[5];//原声明的最简化版
void (*b[10]) (void (*)());//原声明

typedef void (*pFunParam)();//变量名为b,先替换右边部分括号里的,pFunParam为别名一
typedef void (*pFunx)(pFunParam);//再替换左边的变量b,pFunx为别名二

pFunx b[10];//原声明的最简化版

三、两大陷阱

陷阱一:记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。
陷阱二:typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性。

四、typedef 与 #define的区别

案例一:
通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:

typedef char *pStr1;  
#define pStr2 char *;  
pStr1 s1, s2;  
pStr2 s3, s4; 

在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。

案例二:
下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?

typedef char * pStr;  
char string[4] = "abc";  
const char *p1 = string;  
const pStr p2 = string;  
p1++;  
p2++; 

是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:*限定数据类型为char 的变量p2为只读,因此p2++错误

参考资料:
https://blog.csdn.net/qq_31073871/article/details/81258558
https://blog.csdn.net/superhoy/article/details/53504472
《C Primer Plus(第六版)中文版》
《C和指针》

  • 31
    点赞
  • 130
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值