关于typedef:如何阅读C声明?

关于typedef:如何阅读C声明?

How do you read C declarations?

我听说过一些方法,但是没有一个卡住。 我个人试图避免在C语言中使用复杂类型,并尝试将它们分解为组件typedef。

我现在面临着维护所谓的"三星级程序员"的一些遗留代码的麻烦,而且我很难读一些*** code [] []。

您如何阅读复杂的C声明?


本文介绍了一个相对简单的7条规则,如果您发现自己有需要或需要手动阅读C声明,可以使用它们进行阅读:http://www.ericgiguere.com/articles/reading-c-declarations.html

  • Find the identifier. This is your starting point. On a piece of paper, write"declare identifier as".
  • Look to the right. If there is nothing there, or there is a right parenthesis")", goto step 4.
  • You are now positioned either on an array (left bracket) or function (left parenthesis) descriptor. There may be a sequence of these, ending either with an unmatched right parenthesis or the end of the declarator (a semicolon or a"=" for initialization). For each such descriptor, reading from left to right:

    • if an empty array"[]", write"array of"
    • if an array with a size, write"array size of"
    • if a function"()", write"function returning"

    Stop at the unmatched parenthesis or the end of the declarator, whichever comes first.

  • Return to the starting position and look to the left. If there is nothing there, or there is a left parenthesis"(", goto step 6.
  • You are now positioned on a pointer descriptor,"*". There may be a sequence of these to the left, ending either with an unmatched left parenthesis"(" or the start of the declarator. Reading from right to left, for each pointer descriptor write"pointer to". Stop at the unmatched parenthesis or the start of the declarator, whichever is first.
  • At this point you have either a parenthesized expression or the complete declarator. If you have a parenthesized expression, consider it as your new starting point and return to step 2.
  • Write down the type specifier. Stop.
  • 如果您对工具满意,那么我建议使用程序cdecl:http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html


    我通常会使用有时称为"右手顺时针规则"的内容。
    它是这样的:

    • 从标识符开始。
    • 转到它的直接右边。
    • 然后顺时针移动并移至左侧。
    • 顺时针移动并移至右侧。
    • 只要尚未完全解析声明,就可以这样做。

    还有一个附加的元规则必须注意:

    • 如果有括号,请在移出前完成每个级别的括号。

    在这里,"去"和"移动"到某处意味着在该处读取符号。规则是:

    • *-指向的指针
    • ()-函数返回
    • (int, int)-接受两个整数并返回的函数
    • intchar等-intchar
    • []-的数组
    • [10]-十个数组
    • 等等

    因此,例如,int* (*xyz[10])(int*, char)读取为:

    xyz is an

    array of ten

    pointer to

    function taking an int* and a char and returning

    an int*


    一个词:cdecl

    该死的,被打了15秒!


    Cdecl(和c ++ decl)是用于编码和解码C(或C ++)类型声明的程序。

    http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html


    回到我做C的时候,我使用了一个名为" cdecl"的程序。看来它是在Ubuntu Linux中的cutils或cdecl软件包中提供的,并且可能在其他地方可用。


    还有一个基于Web的cdecl版本,非常漂亮。


    cdecl提供了一个命令行界面,因此让我们尝试一下:

    1
    2
    cdecl> explain int ***c[][]
    declare c as array of array of pointer to pointer to pointer to int

    另一个例子

    1
    2
    explain int (*IMP)(ID,SEL)
    declare IMP as pointer to function (ID, SEL) returning int

    但是,在" C Deep Secrets"一书中有一整章的内容,名为" C中的解密声明"。


    刚遇到" C语言的发展"中的一个启发性部分:

    For each object of such a composed type, there was already a way to mention the underlying object: index the array, call the function, use the indirection operator on the pointer. Analogical reasoning led to a declaration syntax for names mirroring that of the expression syntax in which the names typically appear. Thus,

    int i, *pi, **ppi;

    declare an integer, a pointer to an integer, a pointer to a pointer to an integer. The syntax of these declarations reflects the observation that i, *pi, and **ppi all yield an int type when used in an expression. Similarly,

    int f(), *f(), (*f)();

    declare a function returning an integer, a function returning a pointer to an integer, a pointer to a function returning an integer;

    int *api[10], (*pai)[10];

    declare an array of pointers to integers, and a pointer to an array of integers. In all these cases the declaration of a variable resembles its usage in an expression whose type is the one named at the head of the declaration.


    自动化解决方案是cdecl。

    通常,您以使用变量的方式声明变量。例如,您取消引用指针p的方式如下:

    1
    char c = * p

    您以类似的方式声明它:

    1
    char * p;

    多毛的函数指针也是如此。让我们将f声明为老式的"返回指向int的指针的函数的指针",以及一个有趣的外部声明。它是一个函数的指针,因此我们从以下内容开始:

    1
    extern * f();

    它返回一个指向int的指针,所以在前面的某个地方

    1
    extern int * * f(); // XXX not quite yet

    现在哪个是正确的关联性?我不记得了,所以请加上一些括号。

    1
    extern (int *)(* f)();

    声明使用方式。


    常见的可读性问题包括函数指针以及数组实际上是指针,而多维数组实际上是单维数组(实际上是指针)。希望对您有所帮助。

    无论如何,只要您理解声明,也许您就可以找到一种简化声明的方法,以使下一个家伙更易读。


    推荐阅读