在阅读优秀的 c 语言开源程式的时候,我们经常会看到各种复杂的声明,顿时会让我们怀疑人生,怀疑自己是否真的看得懂 c 语言。然而冷静三秒钟,透过现象看本质,发现牛人写的代码并不是“天书”, 也是很好懂的,关键是要冷静和耐心去阅读。
从中的一个例子说起
1(*(void(*)())0)()
下面我们来一步步分析:
我们知道变量的声明方式为:
1int a;
函数的声明方式为:
1int fn();
指针的声明方式为:
1int *a = 10;
函数指针的声明方式为:
1int (*fn)(); //fn 是一个指向返回int型的函数的指针
函数指针的调用方式:
1typedef int (*fn_type)();
2
3int fn() {
4 return 0;
5}
6
7fn_type a = fn;
8
9printf("%d\n", a());
10//或者
11printf("%d\n", (*)a());
最简单的类型转换:
在 c 语言中,去掉变量名,就是变量类型:
1int (*fn)();//fn 是一个指向返回int型的函数的指针
2int (*)(); //表示指向返回int型的函数的指针类型
3
4// 还可以用typedef
5
6typedef int (*fn_type)(); // fn_type 就是指向返回int型的函数指针类型
回到上面的声明,我们先分析里边的部分(void(*)())0
,很显然void (*)()
是一个指向返回 void 类型的函数的指针类型,可以简化为typedef void (*fn_ptr)(); (fn_ptr)0
,
这样写是不是一下子明了了许多,原来是把0
强制类型转换成了fn_ptr
类型,也就是把0
转成了一个指向返回void
的函数的指针类型。这样的话,原式可以等价为((* fn_ptr )0)()
,
实际上就是一个先转型,后调用的过程,即先把 0 转成函数指针,然后再调用函数。
再来看一个例子
1char *(*(*a[])())()
有了前面的基础,我相信再理解这个声明就没有那么困难了。
首先还是从内到外来解读:
1(*a[])()
很显然,在 c 语言中,去掉变量名就是变量类型,这里的 a 是一个指向函数的指针的数组,我们将其看做一个整体a0
,那么再到外层为:
1char *(*a0)()
这样就很显然了,a0
是一个指向返回char *
类型的函数的指针。
那么综合起来解读这个声明即为:a 是一个指向 返回一个 指向返回char *
类型的函数指针类型 的函数指针类型的数组。
哈哈,是不是读起来很绕口,很多时候确实是这样的,为了便于理解,也可参考下面的代码:
1#include <stdio.h>
2
3typedef char * (*f1_ptr)();
4typedef f1_ptr (*f2_ptr)();
5
6char *f1() {
7 return "hello";
8}
9
10f1_ptr f2() {
11 return f1;
12}
13
14int main(int argc, char *argv[])
15{
16 char *(*(*a[1])())();
17 a[0] = f2;
18 printf("%s liubang\n", (a[0]())());
19 return 0;
20}
此外,我们还可以借助一些很好用的开源工具来帮我们解读这些声明,而且有时候,用英文表达这些声明能更好的帮我们解:
1liubang@venux:~$ sudo apt-get install cdecl -y
2liubang@venux:~$ cdecl
3Type `help' or `?' for help
4cdecl> explain char *(*(*a[])())()
5declare a as array of pointer to function returning pointer to function returning pointer to char
6cdecl> declare a as pointer to function returning struct tag
7struct tag (*a)()
评论