在v2ex闲逛发现有人在谈怎么学习c语言,有人推荐tcpl,然后写了个反人类的变量定义 void (*(*f[])())()
,这么复杂的定义在c++实际的项目中其实也不常见,反正我喜欢研究下到底是什么,就花了点时间去看看这个定义,其实复杂的变量定义在csdn有一个人详细的解读过,不过凭着三脚猫的功底,我还是按着自己的理解去解读下吧。
首先提取下变量名,这个就是我们实际定义的变量f,我们定义了变量f,但是类型还未知,反正知道是
void (*(*[])())()
类型的定义。
然后呢,我们看到了左侧的*和右侧的[],我们知道在没有()的情况下,类型是倾向于和右侧的[]结合的,那么我们知道f是一个数组(当然可以把它弱化为对数组的指针,一样的)。
为了简化理解,我们修改一下这个变量的定义。
void (*(*f[1])())()
这样我们就很简单的知道,f是一个数组,有1个元素,剩下未知的就是数组元素的类型了。
我们来提取下数组的元素类型:
void (*(*)())()
的确是反人类的类型,我们依旧按步骤走。我们朝着刚把变量名移走的位置看,看到了*(*)()
的类型声明,那么究竟这个类型是什么呢?啥都不像!可是最像什么呢?对,有这个类型的,也只有函数指针了。
我们按着函数指针的方向走,发现右边的()
不就是代表有没参数么!对,这条路肯定走的通,剩下的就是解析函数的返回值类型了,于是我们继续把返回值的类型提取出来:
void(*)()
这样就很清楚了吧,函数的返回值也是一个函数指针,参数空返回值也为空,这样我们就把这个变量的类型给解出来了。
按白话说,这个变量其实是一个数组(指针),里面的每一个元素(指向的元素)都是一个函数指针,所以这个数组的大小其实是可以知道的。然后这个函数指针,参数为空,返回值也是一个函数指针,返回值的函数指针则是一个参数为空,返回值为空的函数指针。
下面写一个简单的函数来验证下上述的想法。
typedef void(*ReturnFunc)();
void retfn()
{
MessageBox(NULL, "call", "t", MB_OK);
}
ReturnFunc callfn()
{
return retfn;
}
void param(void (*(*f2[])())())
{
f2[0]()();
}
int main() {
void (*(*f1[1])())();
f1[0] = &callfn;
f1[0]()();
void (*(*f2[])())() = f1;
f2[0]()();
param(f1);
return 0;
}