由浅至深->C语言中typedef关键字的经典问题分析

引言:该系列的第三篇文章,哪怕仅一人受益也都达到了我分享的目的!

文章向导
* 令人迷惑的出场
* typedef的基础玩法
* typedef的进阶玩法(各种奇特的声明)

正文
一、令人迷惑的出场
C语言中总是存在着一些字面上使人困扰的关键字,typedef也不例外,明面上使用时给人一种“定义新类型”的感觉,或许你从未思索过上述问题,甚至还有些怀疑是否真的就是如此。实际上,typedef只能给已经存在的数据类型重命名,本质上不能产生新的类型,注意:它针对的是类型,而不是值,这点与#define不同。真相已经揭晓,C语言的创造者淡淡一笑,真的不是我的锅!

二、typedef的基础玩法
这里先介绍typedef关键字的一些简单用法,这也是作为后续进阶的铺垫。

typedef int Int32;

struct _tag_test
{
    int x;
    int y;
};
typedef struct _tag_test Test; //位于已存在类型的后面

typedef struct
{
    int len;
    int array[];
} SoftArray; //struct别名式写法,详情参见第一篇文章

typedef struct _tag_list_node ListNode; //位于待定义类型的前面
struct _tag_list_node
{
    ListNode * next; //结构体指针变量
};

int main()
{
    Int32 i = -100; //int
    //unsigned Int32 j = 0; //error
    Test t;
    SoftArray * sa = NULL;
    ListNode * node = NULL;

    return 0;
}

上面这个简短的例子,可从中挖掘出两点有用的结论:

  • typedef重命名类型时,可位于已存在类型的后面以及待定义类型的前面。当然,上述展示的struct结构体在C语言中并不能算是一种类型,但暂且这样理解也没有什么太大的不妥。
  • 不能用unsigned或signed来修饰typedef重命名后的类型。

三、typedef的进阶玩法
1.奇特的声明
注意:前方高能,请在安全且舒适的环境下细细品读。

int box[8][8]; //int型二维数组
int ** ptr; //指向int型的二维指针
int * ptr[10]; //指针数组,每个元素都是一个指向int的指针
int (*ptr)[10]; //数组指针,指向具有10个元素的int数组
int * ptr[3][4]; //同理为指针数组,略过...
int (*ptr[3])[4]; //数组指针,一个具有3个元素的数组,每个元素都是一个指向具有4个元素的int数组的指针。
char* (*func[3])(char*); //数组指针(3个指针组成的数组),每个指针都指向返回类型为char*的函数,且该函数含有char*的参数。

有点晕? 哈哈,其实我并不是很想解释他们,别打我!先介绍下面这几点规则:

*代表一个指针
()代表一个函数
[]代表一个数组
[]和()具有相同的优先级,都高于间接运算符*的优先级。
[]和()是从左到右结合的,那么在阅读时则应按照先后组合方式逐步剥开。

就以最后一个看起来最复杂的函数指针为例。首先,最中间的位置(*func[3]):[3]代表func为数组,但※号又表明它为指针,合并得到的信息就是数组指针;接着,既然是指针那必定就有指向,再往右看发现另一花括号(char※),则可得出为函数;最后,将中间的func部分给遮住就可以得出注释中的结论。
的确还是有些绕,后面的指针部分的文章,我会力求做到更为简明的描述。

2.typedef化繁为简
上面的那些小点心可读性看起来还真是低呢,确实,事实上简单美一直是人们的一种追求,那么typedef给了我们一次打开美的机会。

(1)数组指针,交个朋友吧!

typedef type(name)[size]; /*命名数组类型的格式*/

typedef int(AINT5)[5];/*如这样,可直接使用AINT5作为类型定义变量*/
AINT5 a; //等价于int a[5];

AINT5* pi; //使用数组类型定义数组指针,等价于int (*pi)[5];
int (*pi)[5]; //直接定义数组指针

看完这个小例子,不知你是否发现这其中的简单和谐之美。

(2)函数指针,认识一下!

typedef type (name)(parameter list) /*命名函数类型的格式*/

typedef int (FUN)(int, int); /*如这样,可直接使用FUN标识定义变量*/
FUN* ptr; //使用函数类型定义指针,等价于int (*ptr)(int, int)

嗯,相信你已经明白它的妙用了,或许你也会与我一样爱上这种语言上的艺术和美感!

参阅资料
C Primer Plus
狄泰软件学院-C语言进阶剖析教程

下期预告:开始步入C语言中老大难的指针以及数组问题的分析!

猜你喜欢

转载自blog.csdn.net/a574780196/article/details/79984605