Happy New Year
伴随着2018的寒冬,2019就这么来临了,互联网裁员也是此起彼伏。公司为裁员各出奇招斗智斗勇。
前有某赞的非人性化工作制度以及惊人论点,现有某蜂以需要逻辑能力为借口进行数学考试。某锤也已倒下,未来怎样,犹未可知。
但显然,一味的担心明显是没有任何用处,不如冷静沉着应对,提升自己,正所谓:金子总会发光的。
c语言中,typedef就是用来给某一个类型定义一个别名。
相当于给一个人起一个外号而已,但外号本就是个可有可无的东西。
从这个角度来看,typedef明明没有存在的必要,可却应用广泛,究竟是为何?
万物存在即有理,既然它可以存在那么久并且得到广泛的应用,那一定是有它的道理。
为了心甘情愿接受typedef的存在,也为了以后更好的使用typedef,决定来分析一下typedef的用法,来看看它究竟有何魔力
typedef的用法大致分为两种
-
为现有的数据类型创建一个别名
-
为复杂的数据类型创建一个别名
为现有数据类型创建一个别名:
比如type作用域unsigned int
1typedef unsigned int U_INT;
规定U_INT是一种unsigned int无符号整型的别称
1U_INT b;//等价于unsigned int b;声明一个unsigned int型的b.
再来看一下type作用于struct
1typedef struct item {
2 char a;
3 int b;
4 } Item;
规定Item是struct item的别称
从目前来看typedef貌似也没起什么不可或缺的作用,只是稍微的省略了一两个单词而已,也不足以说服我接受typedef的存在
但是,如果要封装接口的话用处可就大了,
比如针对上文的Item,如果再进行一个struct封装
1typedef struct node{
2 Item * clause;
3 Item * next;
4 } Node;
接口开发人员提供针对Node的操作方法
1/**file1.h*/
2typedef struct item {
3 char a;
4 int b;
5} Item;
6typedef struct node{
7 Item * clause;
8 Item * next;
9} Node
10void InitialNode(Node * node);
11bool AddNode(Node* node, Item item);
12CopyToNode(Item item, Node * node);
实现接口方法
1/**file1.c*/
2void InitialNode(Node * node){
3 node = NULL;
4 }
5 bool AddNode(Node* node, Item item){
6 Node* last = node;
7 Node* pnew;
8 pnew = (Node*)malloc(sizeof(Node));
9 if(pnew == NULL) {
10 return false;
11 }
12 CopyToNode(item, pnew);
13 pnew->next = NULL;
14 if(last == NULL){
15 last = pnew;
16 }else{
17 while(last->next != NULL){
18 last = last->next;
19 }
20 last->next = pnew;
21 }
22 return true;
23
24 }
25
26 CopyToNode(Item item, Node * node){
27 node->next = item;
28 }
对于接口开发人员来说,InitalNode和AddNode方法的输入相关的是Node指针和Item指针,函数中的操作也是针对Node和Item的整体而言.
那么如果你想替换item,接口函数也无需再重新书写,只需要重新定义一个struct,用typedef重命名为Item即可
1typedef struct custom{
2 int a;
3 int arr[10];
4 char str[100];
5} Item;
item也可以是基本类型
1typedef int Item;
而node无需重新定义,用户依旧可以调用那一套统一接口
如果学过面向对象语言的话,很明显看出来这就是多态啊。用户只需要重新声明一个别名为Item的类型(无论是什么,struct也好,基本类型也好),就可以直接调用统一的接口实现
由此,typedef的意义才真正彰显出来。虽然c语言中没有多态的概念,但是却用typedef实现了多态。使得接口代码有了可移植性。
为复杂的数据类型创建一个别名
比如为数组创建别名
1typedef int INT_ARRAY_100[100];
INT_ARRAY_100是一个数组的别称,该数组含有100个int型元素
1INT_ARRAY_100 arr; //等价于int arr[100];
比如为函数指针创建别名
1typedef char * PF(char *,int *);
PF代表的是返回值为char * ,参数为char*, int*的函数
那么在使用时
1void func(PF pf);//等价于void func(char * pf(char * ,int *)
看起来用typedef确实舒服多了。typedef针对于复杂数据类型,可以让代码看起来更简洁。
那么,其实综上可以看出来,typedef存在不外乎两个原因
-
为复杂的类型创建一个容易识别的简洁的别名
-
为接口的可移植提供遍历
注意:
利用typedef为指针命名时应该注意一点:如下代码中p代表的是char类型的指针
1typedef char * p;
也就是说p本身是一个指针,指针类型为char;
那么问题就来了
1const p
这句代码代表什么意思呢?表示声明一个常量,该常量是char类型的指针。p代表的是指针是一个常量,也就是p所指向的地址不可以改变,但是所指向的值可以修改
那么和以下哪句代码等价呢?
1//声明一个指针,指向常量,可修改指针指向别处,但指针指向的内容不可修改
2const char * p;
3//声明一个常量,但该常量属于指针类型,也就是常亮指针,一旦初始化就不可指向别处地址
4char * const p;
根据注释,不难看出,相当于第二个声明。也就是说可以有如下操作
1 int a = 1;
2 int b = 2;
3 const p = &a;
4 p = &b;//不正确,不能修改p的指向地址
5 *p = b;//正确,可以修改指向地址中存储的值
这就是和#define不同之处了,#define只是单纯的字符串代替
1#define POINT int *
2int one = 1;
3int two = 2;
4const POINT point = &one;
5point = &two;//正确,可以修改p的指向地址
6*point = two;//不正确,不可以修改指向地址中存储的值
https://mp.weixin.qq.com/s/3lR50B3U4aonFG9C-sFQmA