C语言中复杂声明的解读和简化
- 使用声明的优先级规则解读声明
- 解读一个C语言声明,首先要找到声明中的标识符,然后按照优先级次序依次读取
- 优先级从高到低一次是:
- 声明中被括号括起来的部分
- 后缀操作符:()表示这是一个函数,[]表示这是一个数组
- 前缀操作符:*表示这是一个指针
- const关键字后紧跟着类型描述符则说明该const关键字作用于类型说明符,
其它情况则作用于const左边紧邻着第一个*号
例1:下面使用上述规则解读这个声明
char* const *(*p[10])()
标识符为p,p被一对括号包住,所以把括号里面的东西当作一个整体来看,p的后缀是[],则p
是一个数组,p前面有一个星号,表示数组中的元素为指针,(*p[10])后面紧跟着(),则表示
这是一个指向函数的指针,且该函数没有参数,(*p[10])前面的紧挨着*,则表示该函数返 回一个指针,该指针指向一个类型为char的常量指针.
例2:下面使用上述规则解读这个声明
void (*s(int sig,void(*func)(int)))(int);
标识符为s,s被一对括号包住,所以将(*s(int sig,void(*func)(int)))作为一个整体
分析,s后面紧跟着一对括号,则表示s是一个函数,s的第一个参数为int,第二个参数是一个
函数指针,该函数指针指向一个参数为int无返回值的函数;此时函数s的参数解读完毕,那么
剩下未解读的部分都是s的返回值,s的左边紧挨着*号,则表示s的返回值是一个指针,又因为
(*s(int sig,void(*func)(int)))后面紧跟着一对()则表示该指针为函数指针,指向一个参数为int无返回值的函数。
- 使用如下方式解读声明
使用该流程图解析上述例1:
剩余的声明 | 所采取的步骤 | 结果 |
---|---|---|
char* const *(*p[10])() | 第1步 | 表示"p是....",这里先找出声明中的表示符为p |
char* const *(* [10])() | 第2步 | 表示"p是....的数组",这里确定p为数组,接下来 要确定数组p中的元素类型 |
char* const *(* )() | 第5步 | 表示数组元素类型为"指向....的指针",接下来 要确定指针的类型 |
char* const *( )() | 第4步 | *p[10]已经处理完成,去掉用来包裹他们的一对 括号 |
char* const * () | 第2步 | 不符合,转到第3步 |
char* const * () | 第3步 | 表示"无参,返回....的函数",接下来确定函数的 返回值类型 |
char* const * | 第5步 | 表示"指向....的指针" |
char* const | 第5步 | 表示"只读" |
char* | 第5步 | 表示"....的指针" |
char | 第6步 | char |
把上面的解析串起来可推导出:p是一个数组,该数组元素为指向无参并返回指向只读字符类型的指针的函数。
其实上面描述并不容易理解,可以这样描述:p是一个数组,该数组元素为函数指针, 指向函数
没有参数,并返回一个指针,该指针指向只读的字符类型指针
上述的例2就不使用这种方法解读了,太繁琐了,建议使用优先级规则优先级规则解读复杂声明
3. 使用typedef简化复杂声明
使用typedef完全可以使上述声明简单易懂,对于char* const *(*p[10])()这个声明,
由上面分析可知数组p中的元素类型为函数指针,那么可以使用typedef为函数指针取别名
typedef char*const* (*PFN)();
然后在定义指针数组:
PFN fnAry[10];
那么fnAry和p是等价的。
对于
void (*s(int sig,void(*func)(int)))(int);
这个声明,使用typedef简化如下:
typedef void(*PFN1)(int); PFN1 s(int sig,PFN1 pfn);
可以看出使用typedef后,声明得到了极大的简化。