我听说过一些方法,但没有一个能成功。就我个人而言,我尽量避免使用 C 中的复杂类型,并尝试将它们分解为组件 typedef。
我现在面临维护一些来自所谓的“三星级程序员”的遗留代码,而且我很难阅读一些 ***code[][]。
您如何阅读复杂的 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
我通常使用有时被称为“右手顺时针规则”的东西。它是这样的:
还有一个额外的元规则需要注意:
在这里,“去”和“移动”某处意味着阅读那里的符号。规则是:
*
- 指向的指针()
- 函数返回(int, int)
- 函数接受两个整数并返回int
, char
, 等等 - int
, char
, 等等[]
- 数组[10]
- 十个数组因此,例如,int* (*xyz[10])(int*, char)
读作:
xyz 是一个
十个数组
指向的指针
函数采用 int* 和 char 并返回
一个整数*
一个字:cdecl
妈的,被打了15秒!
Cdecl(和 c++decl)是一个用于编码和解码 C(或 C++)类型声明的程序。
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 Deep Secrets”一书中有一整章,名为“Unscrambling declarations in C.
刚刚在“ C语言的发展”中看到了一个启发性的部分:
对于这种组合类型的每个对象,已经有一种方法可以提及底层对象:索引数组、调用函数、在指针上使用间接运算符。类比推理导致名称的声明语法反映了名称通常出现的表达式语法。因此,
int i, *pi, **ppi;
声明一个整数,一个整数指针,一个指向整数指针的指针。这些声明的语法反映了 i、*pi 和 **ppi 在表达式中使用时都会产生 int 类型的观察结果。相似地,
int f(), *f(), (*f)();
声明一个返回整数的函数,一个返回指向整数的指针的函数,一个指向返回整数的函数的指针;
int *api[10], (*pai)[10];
声明一个指向整数的指针数组和一个指向整数数组的指针。在所有这些情况下,变量的声明类似于它在表达式中的用法,其类型是在声明开头指定的类型。
还有一个非常漂亮的基于 Web 的 cdecl 版本。
自动化解决方案是 cdecl。
通常,您以使用它的方式声明变量。例如,您取消引用指针 p,如下所示:
字符 c = * p
你以类似的方式声明它:
字符 * p;
毛茸茸的函数指针也是如此。让我们将 f 声明为旧的“指向函数的指针,返回指向 int 的指针”,以及一个外部声明,只是为了好玩。它是一个指向函数的指针,所以我们从:
外部 * f();
它返回一个指向 int 的指针,所以前面的某个地方有
外部 int * * f(); // XXX 还没有
现在哪个是正确的关联性?我不记得了,所以用一些括号。
extern (int *)(* f)();
以您使用它的方式声明它。
常见的可读性问题包括函数指针和数组实际上是指针这一事实,以及多维数组实际上是一维数组(实际上是指针)。希望对一些人有所帮助。
无论如何,只要您确实理解了声明,也许您可以找到一种简化它们的方法,以使它们对下一个人来说更具可读性。