如何读懂复杂的C声明

如何读懂复杂的C声明


 

       K&R曾经承认:“C语言声明的语法有时会带来严重的问题”。的确,诸如 char * const * ( * next ) ( ) ;  char * ( * c[10]) ( int ** p );之类的声明晦涩难懂,让人迷茫。还好,Peter Van Der Linden在它的经典著作《Expert C Programming》中介绍了两种解开这个难题的方法。

 

     下面介绍读懂C语言声明两法:

     一、优先级法。

          

               A     声明从它的名字开始读取,然后按照优先级顺序依次读取。

               B     优先级从高到低依次是:

                              B. 1     声明中被括号括起来的部分

                              B. 2     后缀操作符:

                                             括号 () 表示这是一个函数

                                             方括号 []  表示这是一个数组

                              B. 3     前缀操作符:星号 * 表示 “指向...的指针”

               C     如果const和(或)volatile关键字的后面紧跟类型说明符(如int,long等),那么它作用于类型说明符。在其他情况下,const和(或)volatile关键字作用于它左边紧邻的指针星号。

          举例说明此法: char * const * (*next)();

               A           首先,看变量名next,并注意到它直接被括号所括住

               B.1        所以先把括号里的东西看为一个整体,得出“next是一个指向...的指针”

               B           然后考虑括号外的东西,在星号前缀和括号后缀之间做出选择

               B.2        B.2规则告诉我们优先级较高的是右边的函数括号,所以得出“next是一个函数指针,指向一个返回...的函数”

               B.3        然后,处理前缀*,得出指针所指的内容

               C          最后,把 char * const 解释为指向字符的常量指针

               概括分析之后,这个声明表示:“next是一个指针,它指向一个函数,该函数返回另一个指针,该指针指向一个类型为char的常量指针”。

     二、符号法。

               步骤如下:

                         1、取最左边的标识符。

                         2、查看标识符右边的下一个符号,如果是方括号 [ ,则对于每一对,表示“...的数组”

                         3、如果是左括号(,则到右括号为止的内容表示“返回...的函数”

                         4、如果左边的符号是一个左括号(,这个括号把已经处理的部分声明组合在一起,直到遇见对应的右括号。然后从第2步重新开始。

                         5、如果左边的符号是下述之一:

                                        const    volatile    *

                              继续向左读取符号,知道所读符号不再是上边那三个之一。如果符号是const,表示“只读”,如果是volatile表示“volatile”,如果是*,表示“指向...的指针”然后重复第4步。

                         6、剩下的符号形成声明的基本类型,剩余的符号一并阅读,如 static unsigned int

               举例说明此法:char * (* c[10] ) (int **p);

                           剩余的声明                           所采取的下一步骤                   结果

                 


                    char * (* c[10])(int **p)                 第1步                              表示“c是...”

                    char * (*   [10])(int **p)                第2步                              匹配,表示“c是...的数组”转下一步

                    char * (*         )(int **p)                第3、4步                          不匹配,转到下一步

                    char * (*         )(int **p)                第5步                               与星号匹配,表示“指向...的指针”,转第4步

                    char * (           )(int **p)                第4步                               与“(”匹配,转到第2步

                    char *              (int **p)                第2步                               不匹配,转下一步

                    char *              (int **p)                第3步                               匹配,表示“返回...的函数,这个函数以int **p为参数”

                    char *                                           第4步                               不匹配,下一步

                    char *                                           第5步                               匹配,表示“指向...的指针”,剩下char,执行第6步

                    char                                              第6步                               直接阅读

                拼在一起,读作:“c是一个数组,它的元素是指向函数的指针,该函数以int **p为参数,返回指向char的指针”。大功告成了!

               

     事实上,以上的解析过程完全可以写成一个程序,用来解析C声明,比如unix中的cdecl。

                         

原文地址:https://www.cnblogs.com/iylc/p/1264666.html