复杂的声明
考虑下面的一个声明:
char *(*(*a[])())();
使用由内到外的阅读方法,并遵循[]和()的结合性强于*的规则,依然很难得到这个声明的准确描述和含义。我们使用另一种方法,“声明模仿使用”:
*(*(*a[])())() 是一个 char
(*(*a[])())() 是一个 指向char
*(*a[])() 是一个 返回指向char的函数
(*a[])() 是一个 指向返回指向char的函数的指针
*a[] 是一个 返回指向返回指向char的函数的指针的函数
a[] 是一个 指向返回指向返回指向char的函数的指针的函数的指针
a 是一个 指向返回指向返回指向char的函数的指针的函数的指针数组
这种复杂的声明用得很少,当我们确实需要使用复杂声明的时候,我们一般不会直接使用一个晦涩难懂的声明语句,而是多次使用typedef来简化处理。
比如:需要声明一个“指向返回指向返回指向char的函数的指针的函数的指针数组a”,初看起来实在是太复杂了,我们可以从里到外逐层进行类型定义:
指向char typedef char *pc;
返回指向char的函数 typedef pc fpc();
指向返回指向char的函数的指针 typedef fpc *pfpc;
返回指向返回指向char的函数的指针的函数 typedef pfpcfpfpc();
指向返回指向返回指向char的函数的指针的函数的指针 typedef fpfpc*pfpfpc;
指向返回指向返回指向char的函数的指针的函数的指针数组 pfpfpc a[];
考虑下面一个奇怪的语句:
(*(void(*)())0)();
这其中包含了类似函数声明的语句和强制类型转换的表达式。
首先要明白C语言关于声明的一条基本规则:按照使用的方式来声明。(另一种说法是:让声明符模仿标识符的最终用法。)
比如:int *g(), (*h)();
*g()就是一个int型数,而(*h)()返回的值也是一个int型值。
一旦我们知道了声明的基本原则,那么强制类型转换也变得容易了:就是把声明语句的分号和变量名称去掉,再用括号把修改后的表达式括起来就OK了。
比如声明:int (*h) (); 声明了一个返回值为int型的函数指针,如果要将某个变量a强制转换为这种类型的指针,就可以使用 (int (*) ())a;
弄清楚这两点,上面的这个语句就好理解了:
首先,(void(*)())0 是将0强制转换为一种函数指针,这种函数返回void类型;
接着,(*(void(*)())0)();解引用这个强制转换后的函数指针,将空参数传递给它,使其执行。