你怎么读C声明?

时间:2008-09-18 00:57:42

标签: c typedef cdecl

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

我现在面临着从一个所谓的“三星级程序员”维护一些遗留代码的问题,而且我很难阅读一些***代码[] []。

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

10 个答案:

答案 0 :(得分:32)

本文解释了一个相对简单的7条规则,如果您发现自己需要或需要手动执行此操作,您可以阅读任何C声明:http://www.ericgiguere.com/articles/reading-c-declarations.html

  
      
  1. 找到标识符。这是你的出发点。在一张纸上,写下“声明标识符为”。
  2.   
  3. 向右看。如果那里没有任何内容,或者右括号“)”,请转到第4步。
  4.   
  5. 您现在位于数组(左括号)或函数(左括号)描述符上。可能存在这些序列,以不匹配的右括号或声明符的结尾(分号或“=”表示初始化)结束。对于每个这样的描述符,从左到右阅读:

         
        
    • 如果是空数组“[]”,则写入“数组”
    •   
    • 如果有一个大小的数组,写“数组大小为”
    •   
    • 如果函数“()”,则写“返回函数”
    •   
         

    停在不匹配的括号或声明者的末尾,以先到者为准。

  6.   
  7. 返回起始位置并向左看。如果那里什么也没有,或者左括号“(”,转到第6步。
  8.   
  9. 您现在位于指针描述符“*”上。左边可能有一个序列,以左括号“(”或声明符的开头结束。从右到左阅读,每个指针描述符写“指向”。停在不匹配的括号或声明者的开头,以先到者为准。
  10.   
  11. 此时您有一个带括号的表达式或完整的声明符。如果您有带括号的表达式,请将其视为新的起点并返回步骤2.
  12.   
  13. 记下类型说明符。停止。
  14.   

如果您对某个工具没问题,那么我建议使用该程序cdeclhttp://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html

答案 1 :(得分:22)

我通常使用有时被称为“右手顺时针规则”的东西。 它是这样的:

  • 从标识符开始。
  • 走到它的右边。
  • 然后顺时针方向移动到左侧。
  • 顺时针移动并向右移动。
  • 只要尚未完全解析声明,请执行此操作。

还有一个必须要处理的额外元规则:

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

在这里,“前进”和“移动”某处意味着在那里阅读符号。规则是:

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

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

  

xyz是

     

十个数组

     

指向

的指针      

函数接受一个int *和一个char并返回

     

一个int *

答案 2 :(得分:6)

一个字:cdecl

Damnit,被打15秒!

答案 3 :(得分:4)

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

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

答案 4 :(得分:3)

当我做C时,我使用了一个名为“cdecl”的程序。它似乎是在cutils或cdecl包中的Ubuntu Linux中,它可能在其他地方可用。

答案 5 :(得分:1)

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

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

另一个例子

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

然而,在“C Deep Secrets”一书中有一整章关于这一点,名为“在C中解读声明。

答案 6 :(得分:1)

还有一个非常漂亮的Web-based version of cdecl

答案 7 :(得分:0)

常见的可读性问题包括function pointers以及arrays are really pointersmultidimensional arrays are really single dimension arrays (which are really pointers).希望帮助某些人的事实。

无论如何,只要你理解了这些声明,也许你可以找到一种方法来简化它们,使它们对下一个人来说更具可读性。

答案 8 :(得分:0)

自动解决方案是cdecl。

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

char c = * p

你以类似的方式宣布它:

char * p;

毛茸茸的函数指针也是如此。让我们声明f是一个很好的旧“指向函数返回指向int的指针”,并且外部声明只是为了搞笑。它是一个指向函数的指针,所以我们从:

开始
extern * f();

它返回一个指向int的指针,因此前面的某处有

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

现在哪个是正确的关联性?我永远不会记得,所以请使用一些括号。

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

以你使用它的方式声明它。

答案 9 :(得分:0)

刚刚看到“The Development of the C Language”中的一个有启发性的部分:

  

对于这种组合类型的每个对象,已经有一种方法可以提及底层对象:索引数组,调用函数,在指针上使用间接运算符。类比推理导致了一个声明语法,用于反映名称通常出现的表达式语法的名称。因此,

     

int i, *pi, **ppi;

     

声明一个整数,一个指向整数的指针,一个指向整数指针的指针。这些声明的语法反映了在表达式中使用i,* pi和** ppi都会产生int类型的观察结果。类似地,

     

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

     

声明一个返回整数的函数,一个返回指向整数的指针的函数,一个返回一个整数的函数的指针;

     

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

     

声明一个指向整数的指针数组,以及一个指向整数数组的指针。在所有这些情况下,变量的声明类似于在表达式中的用法,该表达式的类型是在声明的头部命名的类型。