C语言声明的优先级规则
今天看《C专家编程》,其中由有一张讲声明,其中讲声明的优先级很有用,现在记录一下,以备后期查看.
- 声明从它的名字开始读取,然后按照优先级的顺序依次读取.
- 优先级从高到低依次是:
- 声明中括号括起来的部分
- 后缀操作符: 括号() 表示这是一个函数,返回…的函数 方括号[]表示这是一个数组
- 前缀操作符: 星号*表示"指向…的指针"
- 如果const和(或)volatile关键字后面紧跟类型说明符(如:int,long等),那么他作用于类型说明符,在其他情况下, const和(或)volatile关键字作用于它左边紧邻的指针星号, 这个指针是…类型
实例
1. char * const *(*next)()
我们来分析上面的这个声明
- 根据上面的规则1, 确定名字是next.其中括号括起来的部分是(*next)
- 根据2.3确认next是指向…的指针.
- 分析完了(*next),然后我们将(*next)作为一个整体. 再根据2.2的原则,(*next)后边是一个括号,便是一个函数,说明next现在是: 指向函数的指针, 指向一个返回…的函数,此时(*next)()是一个整体.
- 再根据2.3, 处理前缀(next)()的前缀"",说明这个函数返回一个指针,这个指针指向…类型.将*(*next)()作为一个整体.
- 根据3的原则,const修饰的时他左边紧邻的指针星号.char * const说明是一个指向char类型的常量指针.
所以最后总结起来就是: next是一个指针,它指向一个指针,该函数返回另一个指针,这个指针指向一个类型为char的常量指针.
2. void ( *signal(int sig, void(*func)(int) ))( int )
我们来分析上面的这个声明:
我们根据上面的规则进行分析,首先先找到声明,我们从左到右查找最内层的声明,找到如下声明:
void(*func)(int)
说明func是一个指向函数的指针.该函数的形参为int,返回值为void,
- 我们接下来注意到了前面的int sig我们发现他和void(*func)(int)是平级的,这说明func不是我们要说明的东西,因为我们不可能声明两个.
再往前分析,为我们注意到剩下的部分
void ( *signal( )) ( int )
根据上面的经验,signal才是我们的要声明的的东西.
- 根据规则2,我们发现signal是一个函数(因为signal后边跟的时括号,而且后缀的优先级比前缀高),这就确定了signal得属性,它是一个函数.
我们再来看signal这个函数的特殊性. 现在剩下的部分是
void (* ..... )(int)
我们分析剩下的部分.由规则2.1,我们分析(* …)是一个指针,后边跟着(int),所以是一个函数指针,这个函数的形参是int,返回值时void
现在我们基本分析完了,把我们分析出来的总结一下:
signal 是一个函数,他返回一个函数指针,返回的这个函数指针的形参是int,返回值是void. signal这个函数的形参有两个,第一个就是int, 第二个形参是一个函数指针,这个函数指针func的形参是int,返回值是void.我们可以发现signal这个函数的第二个形参,和它本身的返回值类型相同的
使用typedef来理解signal定义.
signal这个函数的定义,基本上是c语言中最复杂的声明类型,我们可以通过typedef来帮助我们理解signal的定义. 首先定义如下:
typedef void(*ptr_to_func)(int);
我们定义ptrtofunc为一个指针,他指向一个函数,这个函数的形参是int,返回值为void 我们再来看signal的定义
void ( *signal(int sig, void(*func)(int) ))( int )
根据我们上面的分析的分析我们可以做如下的简化
ptr_to_func signal(int sig, ptr_to_func func);
这样看起来是不是清爽很多!