你如何阅读C声明?
我听说过一些方法,但没有一个卡住了。 我个人尽量避免在C中的复杂types,并尝试将它们分解成组件types定义。
我现在正在维护一个所谓的“三星级程序员”的遗留代码,而且我正在阅读一些***代码[] []。
你如何阅读复杂的C声明?
这篇文章解释了一个相对简单的7条规则,可以让你阅读任何C声明,如果你发现自己想要或者需要手动这样做: http : //www.ericgiguere.com/articles/reading-c-declarations.html
- find标识符。 这是你的出发点。 在一张纸上写上“声明标识符为”。
- 向右看。 如果没有任何东西,或者有右括号“)”,那么转到步骤4。
您现在位于数组(左括号)或函数(左括号)描述符上。 可能有这些序列,以无匹配的右括号或声明符的末尾(分号或用于初始化的“=”)结束。 对于每个这样的描述符,从左到右阅读:
- 如果一个空数组“[]”,写“数组”
- 如果一个数组的大小,写“数组大小”
- 如果函数“()”写入“函数返回”
停在不匹配的括号或者说明符的末尾,以先到者为准。
- 返回到开始位置,向左看。 如果什么都没有,或者有左括号“(”,转到步骤6。
- 您现在位于指针描述符“*”上。 在左边可能有一个序列,结尾是一个不匹配的左括号“(”或声明符的开始。从右向左读取,每个指针描述符写入“指向”。停在不匹配的括号处或宣布者的开始,以先到者为准。
- 在这一点上,你有一个加括号的expression式或完整的声明。 如果你有一个加括号的expression式,把它作为你的新起点,并返回到步骤2。
- 写下types说明符。 停止。
如果你对一个工具很好,那么我第二个build议使用程序cdecl
: http : cdecl
我通常使用什么有时被称为“右手顺时针规则”。 它是这样的:
- 从标识符开始。
- 转到它的右侧。
- 然后顺时针移动到左侧。
- 顺时针移动到右侧。
- 只要声明没有完全parsing,就这样做。
还有一个额外的元规则需要注意:
- 如果有括号,在移出之前完成括号的每个级别。
在这里,“去”和“移动”的地方意味着在那里读取符号。 规则是:
-
*
– 指向 -
()
– 函数返回 -
(int, int)
– 取两个整数并返回的函数 -
int
,char
等 –int
,char
等 -
[]
– 数组 -
[10]
– 十个数组 - 等等
所以,例如, int* (*xyz[10])(int*, char)
被读为:
xyz是一个
十个数组
指向
函数采取一个int *和一个字符,并返回
一个int *
一个字: cdecl
该死,被殴打15秒!
Cdecl(和c ++ decl)是用于编码和解码C(或C ++)types声明的程序。
http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html
当我做C时,我使用了一个名为“cdecl”的程序。 看来它在Ubuntu Linux中的cutils或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深度秘密”一书中有一整章,名为“在C中解读声明”
问候弗里德里希
还有一个基于Web的cdecl版本,非常漂亮。
常见的可读性问题包括函数指针和数组实际上是指针 ,而multidimensional array实际上是单维数组(实际上是指针)。 希望有一些帮助。
无论如何,只要你理解了声明,也许你可以想出一种方法来简化它们,使它们对下一个人更具可读性。
自动化解决scheme是cdecl。
一般来说,你使用它的方式声明一个variables。 例如,您可以像下面那样取消引用指针p:
char c = * p
你用类似的方式声明它:
char * p;
多毛的函数指针也一样。 让我们声明f是很好的“返回指向int的函数的指针”,而一个外部声明只是有趣的。 这是一个函数的指针,所以我们从下面开始:
extern * f();
它返回一个指向int的指针,所以在前面的某个地方有
extern int * * f(); // XXX还不完全
现在哪个是正确的结合? 我永远不会记住,所以用一些括号。
extern(int *)(* f)();
声明它的使用方式。
从右到左阅读。
***code[][]
- 代码[] []是一个multidimensional array
- * code [] []是一个multidimensional array指针
- ** code [] []是一个指针的multidimensional array指针
- *** code [] []是一个多指针数组指针,指向一个指针
刚刚在“ C语言的发展 ”中遇到了一个照明部分:
对于这种组合types的每个对象,已经有一种方法来提及底层对象:索引数组,调用函数,在指针上使用间接运算符。 类比推理导致名称的声明语法镜像名称通常出现的expression式语法的名称。 从而,
int i, *pi, **ppi;
声明一个整数,一个指向一个整数的指针,一个指向一个整数指针的指针。 这些声明的语法反映了当在expression式中使用时,我,* pi和** ppi都会产生一个inttypes。 同样的,
int f(), *f(), (*f)();
声明一个函数返回一个整数,一个函数返回一个指向一个整数的指针,一个返回一个整数的函数的指针;
int *api[10], (*pai)[10];
声明一个指向整数的指针数组,以及一个指向整型数组的指针。 在所有这些情况下,variables的声明类似于在声明头部命名的expression式中的用法。