C语言非常难理解的是指针,可是比指针还难理解的是什么呢?我想莫非是C语言的声明了。
比如看下一个系统调用signal()的函数声明:
void (*signal(int sig, void(*func)(int))) (int);
是不是很晕乎?从哪个标识符开始读,singnal?sig?还是int?往左读还是往右读?
其实理解了C语言声明的优先级规则就好办了。
A 声明从它的名字开始读取,然后按照优先级的顺序依次读取。
B 优先级从高到低:
B.1标识符被小括号扩起来的那部分
B.2后缀操作符:( )表示这是一个函数,[]表示这是一个数组。
B.3前缀操作符:星号*表示“指向...的指针”
C 如果const和(或)volatile关键字的后面紧跟类型说明符(int,long等)那么它作用于类型说明符,否则往前看,关键字作用于左边紧邻的类型符或指针星号。
好了,理论用于实践,来看一个例子。
char * const *(*next)();
首先,读到next,往左前缀是*,表示next是一个指针,再后面(),说明next指向函数,函数的返回值是指针,指针指向char*const,表示指向字符类型的常量指针(const作用于指针)。
再来看一个
char *(* c[10])(int **p)
分析:c是一个数组,数组的元素个数为10,元素是指针,这些指针指向函数,函数的参数是int **p(指向指针的指针),函数的返回类型是char *(字符指针)。
好了,再回头看singal()的声明:
void (*signal(int sig, void(*func)(int))) (int);
分析:signal是一个函数,signal函数的参数,一个是int sig,还有一个是 void(*func)(int), 表示一个函数指针,指向一个参数为int,返回void的函数。
signal函数的返回也是一个函数指针,也是指向一个一个参数为int,返回void的函数。
这样就比较清楚了。像庖丁解牛一样。这时你发现了没有signal还是挺绕,不够简洁,看分析中蓝色字体,是不是几乎一样?
试试typedef吧。
typedef void (*ptr_to_func)(int);
为一个类型取了一个新名字,该类型是指向一个参数为int,返回void的函数指针。这样signal就可以这么声明了:
ptr_to_func singal(int sig, ptr_to_func func);
是不是很简洁,当然,如果不考虑可读性,还可以更简洁(不推荐啊)
typedef void (*A)(int); A singal(int sig, A func);
Note: typedef只是给某种类型取一个新名字,并不是声明一种新的类型。
---End---