zoukankan      html  css  js  c++  java
  • 如何阅读复杂的C类型声明

    阅读复杂的C类型声明,通常采用右左法则,也就是Clockwise/Spiral Rule (顺时针/螺旋法则)。 本文将首先介绍工具(cdecl)(个人比较偏好使用工具提高学习和工作效率),然后中英文对照翻译一下著名的文章The ``Clockwise/Spiral Rule''

    1. 工具(cdecl)

    1.1 命令行(cdecl)

    在Ubuntu上,使用如下命令安装cdecl。

    $ sudo apt-get install cdecl

    如何使用cdecl,举几个例子:

    $ cdecl -i
    Type `help' or `?' for help
    cdecl> explain int *foo[3]
    declare foo as array 3 of pointer to int
    cdecl> 
    cdecl> explain int (*foo)[3]
    declare foo as pointer to array 3 of int
    cdecl> 
    cdecl> explain void (*signal(int, void (*)(int)))(int);
    declare signal as function (int, pointer to function (int) returning void) returning pointer to function (int) returning void
    cdecl> 
    cdecl> exit
    $

    注意: 阅读C++类型声明,请使用工具c++decl。

    1.2 在线服务 (https://cdecl.org/

    这个在线服务实在是太贴心了,体验截图如下:

    2. 文章(The ``Clockwise/Spiral Rule"

    [This was posted to comp.lang.c by its author, David Anderson, on 1994-05-06.]

    The ``Clockwise/Spiral Rule'' | 顺时针/螺旋法则
    By David Anderson
    There is a technique known as the ``Clockwise/Spiral Rule'' which enables any C 
    programmer to parse in their head any C declaration! 
    C程序员们如果使用"顺时针/螺旋法则",就可以看懂任何C语言类型声明。
    There are three simple steps to follow:
    一共分为三步,描述如下:
    1. Starting with the unknown element, move in a spiral/clockwise direction; when ecountering the following elements replace them with the corresponding english statements: 从未知元素(变量名?)开始,沿着顺时针螺旋移动。每次遇到以下几种符号,把它换成相应的句子:
    [X] or [] => Array X size of... or Array undefined size of... (type1, type2) => function passing type1 and type2 returning... * => pointer(s) to... 2. Keep doing this in a spiral/clockwise direction until all tokens have been covered. 反复地沿着顺时针/螺旋方向做上述动作,直到所有的符号都被遍历到;
    3. Always resolve anything in parenthesis first!
    如果遇到括号,一定要先确定括号内的类型。
    Example #1: Simple declaration | 简单声明
                         +-------+
                         | +-+   |
                         | ^ |   |
                    char *str[10];
                     ^   ^   |   |
                     |   +---+   |
                     +-----------+
    
    Question we ask ourselves: What is str? 
    问题: str是什么? ``str is an...
    ``str的类型是... We move in a spiral clockwise direction starting with `str' and the first character we see is a `[' so, that means we have an array, so... 从"str"开始,沿顺时针做螺旋移动,遇到的第一个符号是"["。所以,它是一个数组。所以...
    ``str is an array 10 of... ``str是一个元素类型为...的长度为10的数组 ...
    Continue in a spiral clockwise direction, and the next thing we encounter is the `*' so, that means we have pointers, so... 继续沿顺时针做螺旋移动,下一个遇到的符号是'*'。这意味着有指针。所以...
    ``str is an array 10 of pointers to...
    ``str是一个元素类型为指向...的指针的长度为10的数组 ... Continue in a spiral direction and we see the end of the line (the `;'), so keep going and we get to the type `char', so...
    继续沿顺时针做螺旋移动,这一行最后的符号是';', 继续沿顺时针做螺旋移动,遇到类型'char',所以 ... ``str is an array 10 of pointers to char''
    ``str是一个元素类型为指向char类型的指针的长度为10的数组 We have now ``visited'' every token; therefore we are done!
    我们已经"遍历"了每一个符号。收工!
    Example #2: Pointer to Function declaration | 函数指针声明
    
                         +--------------------+
                         | +---+              |
                         | |+-+|              |
                         | |^ ||              |
                    char *(*fp)( int, float *);
                     ^   ^ ^  ||              |
                     |   | +--+|              |
                     |   +-----+              |
                     +------------------------+
    
    Question we ask ourselves: What is fp?
    问题: fp是什么类型? ``fp is a... Moving in a spiral clockwise direction, the first thing we see is a `)'; therefore, fp is inside parenthesis, so we continue the spiral inside the parenthesis and the next character seen is the `*', so...
    沿顺时针做螺旋移动,第一个遇到的是")"。我们发现,fp被放在一个()内。我们必须先留在()内,
    继续沿着顺时针做螺旋移动。下一个遇到的符号是"*"。所以...
    ``fp is a pointer to...
    ``fp是一个指向...的指针 We are now out of the parenthesis and continuing in a spiral clockwise direction, we see the `('; therefore, we have a function, so...
    离开了括号,继续沿顺时针做螺旋移动。我们遇到"("。因此,这是一个函数。所以... ``fp is a pointer to a function passing an int and a pointer to float returning...
    ``fp是一个指向函数的指针,函数参数为一个int型和一个float型指针,返回值为... Continuing in a spiral fashion, we then see the `*' character, so...
    继续沿顺时针做螺旋移动,遇到了"*",所以... ``fp is a pointer to a function passing an int and a pointer to float returning a pointer to...
    ``fp是一个指向函数的指针,函数参数为一个int型和一个float型指针,返回值为
    一个指向...的指针
    Continuing in a spiral fashion we see the `;', but we haven't visited all tokens, so we continue and finally get to the type `char', so...
    继续沿顺时针做螺旋移动,遇到了";",但是我们还没有遍历完所有符号,于是继续绕圈圈,
    最后遇到类型"char", 所以... ``fp is a pointer to a function passing an int and a pointer to float returning a pointer to a char''
    ``fp是一个指向函数的指针,函数参数为一个int型和一个float型指针,返回值为
    一个指向char类型的指针"
    Example #3: The ``Ultimate'' | 终极难题
    
                          +-----------------------------+
                          |                  +---+      |
                          |  +---+           |+-+|      |
                          |  ^   |           |^ ||      |
                    void (*signal(int, void (*fp)(int)))(int);
                     ^    ^      |      ^    ^  ||      |
                     |    +------+      |    +--+|      |
                     |                  +--------+      |
                     +----------------------------------+
    
    Question we ask ourselves: What is `signal'?
    问题: signal是什么?
    Notice that signal is inside parenthesis, so we must resolve this first!
    注意signal在括号内,于是我们必须先搞清楚括号内的类型! Moving in a clockwise direction we see `(' so we have...
    沿着顺时针移动,遇到"(",所以... ``signal is a function passing an int and a...
    ``signal 是一个函数,该函数的参数为一个整数和... Hmmm, we can use this same rule on `fp', so... What is fp? fp is also inside parenthesis so continuing we see an `*', so...
    嗯嗯,我们可以用同样的规则来确定fp的类型,那么...fp是什么类型? fp也在括号内。所以,继续绕圈圈,
    我们遇见"*"。所以...
    fp is a pointer to...
    fp是一个指向...的指针 Continue in a spiral clockwise direction and we get to `(', so...
    继续沿顺时针方向绕圈圈,我们遇到'(',所以... ``fp is a pointer to a function passing int returning...''
    ``fp是一个指向一个参数为int,返回值是...的函数的指针 Now we continue out of the function parenthesis and we see void, so...
    离开函数参数的括号之后,我们遇见void。所以... ``fp is a pointer to a function passing int returning nothing (void)''
    ``fp是一个指向参数为int,什么也不返回(返回void)的函数的指针。 We have finished with fp so let's catch up with `signal', we now have...
    解析fp部分结束了。回到signal的类型。目前是... ``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning...
    ``signal是一个参数为一个int和一个指向一个参数为int,什么也不返回的函数的指针,
    返回值为...的函数。 We are still inside parenthesis so the next character seen is a `*', so...
    我们还在括号内。下一个符号是"*"。所以... ``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to...
    ``signal是一个参数位一个int和一个指向一个参数为int,什么也不返回的函数的指针,
      返回值为指向...的指针的函数。 We have now resolved the items within parenthesis, so continuing clockwise, we then see another `(', so...
    现在,括号内的类型已经解决了。继续绕圈圈,遇到另一个"("。所以... ``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning...
    ``signal是一个参数位一个int和一个指向一个参数为int,什么也不返回的函数的指针,
      返回值为指向一个参数为int,返回值为...的函数的指针的函数。 Finally we continue and the only thing left is the word `void', so the final complete definition for signal is:
    继续绕圈圈,最后一个符号就是最左边的"void"。所以,signal的最终定义就是: ``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning nothing (void)''
    ``signal是一个参数位一个int和一个指向一个参数为int,什么也不返回的函数的指针,
      返回值为指向一个参数为int,什么也不返回的函数的指针的函数。" The same rule is applied for const and volatile. For Example:
    同样的规则可用于const和volatile。例如: const char *chptr; Now, what is chptr??
    那么现在,chptr是什么类型?? ``chptr is a pointer to a char constant''
    ``chptr是一个指向char型常量的指针变量。" How about this one:
    下面这个呢? char * const chptr; Now, what is chptr??
    现在,chptr又是什么?? ``chptr is a constant pointer to char''
    ``chptr是一个指向char型变量的指针常量。" Finally: 最后一道题:
    volatile char * const chptr; Now, what is chptr?? 现在,chptr又是什么类型??
    ``chptr is a constant pointer to a char volatile.''
    ``chptr是一个指向char volatile型变量的指针常量。"
    Practice this rule with the examples found in K&R II on page 122.
    请使用此规则对K&R II第122页上的例子做练习。

    Copyright © 1993,1994 David Anderson
    This article may be freely distributed as long as the author's name and this notice are retained.

    本文可以自由地发布,唯一需要保留的就是作者的名字和这条提示。

    参考文献

    结束语: 此时无声胜有声

    cdecl> explain void (*signal(int, void (*)(int)))(int);
    declare signal as function (int, pointer to function (int) returning void) returning pointer to function (int) returning void
  • 相关阅读:
    自定义cell
    微信界面
    设置字体阴影
    Xcode 7新特性Lightweight Generics 轻量级泛型与__kindof修饰符
    @synchronized 是递归锁,类似NSRecursiveLock,递归调用不会引起死锁,而NSLock是非递归锁。
    Your build settings specify a provisioning profile with the UUID, no provisioning profile was
    NSOperationQueue与GCD
    Objective-C中继承和类别的比较:category&Inherit
    iOS 事件处理机制与图像渲染过程
    [iOS]用instancetype代替id作返回类型有什么好处?(转)
  • 原文地址:https://www.cnblogs.com/idorax/p/7714963.html
Copyright © 2011-2022 走看看