zoukankan      html  css  js  c++  java
  • 如何读懂复杂的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。

                             

  • 相关阅读:
    友元类和友元函数
    C++中构造函数和析构函数调用的时机
    Linux 下svn恢复到某一版本
    lua 中pairs 和 ipairs区别
    孤儿进程与僵尸进程
    union
    关于C++ const 的全面总结
    后台管理左侧菜单
    全选-反选-取消
    Dom-直接 /间接选择器
  • 原文地址:https://www.cnblogs.com/iylc/p/1264666.html
Copyright © 2011-2022 走看看