我听说过一些方法,但都没有卡住。我个人试图避免C中的复杂类型,并尝试将它们分解为组件typedef。
我现在面临着从一个所谓的“三星级程序员”维护一些遗留代码的问题,而且我很难阅读一些***代码[] []。
你如何阅读复杂的C声明?
本文解释了一个相对简单的7条规则,如果您发现自己需要或需要手动执行此操作,它将允许您阅读任何C声明:http://www.ericgiguere.com/articles/reading-c-declarations.html
- 找到标识符。这是你的出发点。在一张纸上,写“声明标识符为”。
- 向右看。如果那里没有任何东西,或者右括号“)”,请转到第4步。
- 您现在位于数组(左括号)或函数(左括号)描述符上。可能存在这些序列,以不匹配的右括号或声明符的结尾(分号或“=”表示初始化)结束。对于每个这样的描述符,从左到右阅读: 如果一个空数组“[]”,写“数组” 如果一个大小的数组,写“数组大小” 如果函数“()”,写“函数返回” 停在不匹配的括号或声明符的末尾,以先到者为准。
- 返回起始位置并向左看。如果那里什么也没有,或者左括号“(”,转到第6步。
- 您现在位于指针描述符“*”上。左边可能有一个序列,以左括号“(”或声明符的开头结束。从右到左阅读,每个指针描述符写“指向”。停在不匹配的括号或声明者的开头,以先到者为准。
- 此时,您有一个带括号的表达式或完整的声明符。如果您有带括号的表达式,请将其视为新的起点并返回步骤2。
- 记下类型说明符。停止。
如果你对一个工具没问题,那么我第二个建议使用程序cdecl
:http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html
刚刚遇到“The Development of the C Language”的一个有启发性的部分:
对于这种组合类型的每个对象,已经有一种方法可以提及底层对象:索引数组,调用函数,在指针上使用间接运算符。类比推理导致了一个声明语法,用于反映名称通常出现的表达式语法的名称。从而,
int i, *pi, **ppi;
声明一个整数,一个指向整数的指针,一个指向整数指针的指针。这些声明的语法反映了在表达式中使用i,* pi和** ppi都会产生int类型的观察结果。同样的,
int f(), *f(), (*f)();
声明一个返回整数的函数,一个返回指向整数的指针的函数,一个返回整数的函数的指针;
int *api[10], (*pai)[10];
声明一个指向整数的指针数组,以及一个指向整数数组的指针。在所有这些情况下,变量的声明类似于在表达式中的用法,该表达式的类型是在声明的头部命名的类型。
我通常使用有时被称为“右手顺时针规则”的东西。它是这样的:
还有一个额外的元规则需要注意:
在这里,“前进”和“移动”某处意味着在那里阅读符号。规则是:
*
- 指向()
- 功能返回(int, int)
- 功能采取两个整数并返回int
,char
等 - int
,char
等。[]
- 数组[10]
- 十个阵容因此,例如,int* (*xyz[10])(int*, char)
读作:
xyz是一个
一排十
指针
函数接受一个int *和一个char并返回
一个int *
一个字:cdecl
Damnit,被打15秒!
Cdecl(和c ++ decl)是一个用于编码和解码C(或C ++)类型声明的程序。
http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html
回到我做C的时候,我使用了一个名为“cdecl”的程序。它似乎是在cutils或cdecl包中的Ubuntu Linux中,它可能在其他地方可用。
还有一个很漂亮的Web-based version of cdecl。
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中解读声明”。
常见的可读性问题包括function pointers和arrays are really pointers的事实,以及multidimensional arrays are really single dimension arrays (which are really pointers).希望帮助一些。
在任何情况下,每当你理解声明时,也许你可以想出一种简化它们的方法,使它们对下一个人来说更具可读性。
自动化解决方案是cdecl。
通常,您以使用它的方式声明变量。例如,您取消引用指针p,如下所示:
char c = * p
你以类似的方式声明它:
char * p;
毛茸茸的函数指针也是如此。让我们声明f是一个很好的旧“指向函数返回指向int的指针”,并且外部声明只是为了搞笑。它是一个指向函数的指针,所以我们从:
extern * f();
它返回一个指向int的指针,所以在前面的某处就有了
extern int * * f(); // XXX not quite yet
现在哪个是正确的关联性?我永远不会记得,所以请使用一些括号。
extern (int *)(* f)();
以你使用它的方式声明它。