C语言之复杂指针详解
在《C陷阱与缺陷》第二章第一节中有这样一个声明:
(*(void(*)())0)();
看到这样的表达式估计让不少人都“不寒而栗”了吧,其实虽然看起来复杂,但是构造这类表达式其实只有一条简单的规则:按照使用的方式来声明。
首先先介绍一个著名的解析法则:右左法则:首先从圆括号起,然后向右看,然后向左看,每当遇到圆括号时,就调转阅读方向,当括号内的内容解析完毕,就跳出这个括号,重复这个过程直到表达式解析完毕。
其实我们发现,所谓复杂指针离不开指针函数,函数指针,指针数组,函数指针这四个概念并且括号,*比较多,其实只要我们仔细分析这些看起来复杂的表达式,其实他的逻辑也是很清晰的。
举个例子,使用右左法则解析复杂的表达式:
Int *(*(*pfun)(int *))[10];
用右左法则解析这个表达式,首先要找到未定义的标识符pfun,当往右看的时候遇到括号,于是调转方向,再朝相反的方向看,pfun遇到了*,说明pfun是一个指针,再往左看又遇到了括号,因此又要调转方向,遇到的是另外一个括号,因此说明指针所指向的是一个函数,函数的参数是一个整型指针。然后又向相反的方向看,又遇到了一个*,说明该函数的返回值又是一个指针,在往左看又遇到括号,所以再次调转方向,把内侧的括号里的内容看完,出了括号遇到的是数组,说明指针所指向的函数的返回值类型的指针指向的是数组,这有点向绕口令,但是还是有逻辑可循的。
但是右左法则确实有点麻烦,我们这样看上面这个表达式:首先fpun是一个指向函数的函数指针,该函数有一个整型指针类型的参数并且返回值也是一个指针,所返回的类型指向的是一个数组,并且这个数组有10个元素,每个元素是整型指针类型。
接下来我们在回过头来看文章最开始的那个表达式:
(*(void(*)())0)();
我们先看括号里面的内容,首先0被强制转换为一个返回值为void类型,没有参数的函数的函数指针,指针(void)(*)()0)指向了一个函数。
要想很好的解决这个问题,选择使用typedef是一个很好的方式。