[英]A way to efficiently parse function pointer declaration syntax
所以,直到现在,我很确定我的精神指针到函数解析器能够解析即使是最难的指针......我错了! 在阅读一些遗留代码时,我发现了这一点:
void (*(*somename)(void (*)()))(void (*)());
显然,这意味着将somename
声明为指向函数的指针(指向返回void
函数的指针)返回指向函数的指针(指向返回void
函数的指针)返回void
(至少根据http://cdecl.org )。
似乎我过于简化了函数指针声明的工作方式。 我很确定语法是return-type(*variable-name)(argument-types...)
。 它适用于很多情况,但不适用于复杂的情况,如上述。 我怎么能去阅读这样不寻常和复杂的声明,而不必考虑所有的语法规则,并试图弄清楚我是应该从左到右阅读还是反向阅读或以其他奇怪的方式阅读?
我的一位教授教我们如何使用“左右规则”来做到这一点。 他在这里记录了这一点。
这是我将它应用于此声明的方式(从标识符开始向右移动)。
void (*(*somename)(void (*)()))(void (*)());
+-------^ somename
void (*(*somename)(void (*)()))(void (*)());
^--------+ is pointer
void (*(*somename)(void (*)()))(void (*)());
^---------+ (move left)
void (*(*somename)(void (*)()))(void (*)());
+----------^ to function
void (*(*somename)(void (*)()))(void (*)());
+----------------------^ taking (void (*)())
void (*(*somename)(void (*)()))(void (*)());
^-----------------------+ returning pointer
void (*(*somename)(void (*)()))(void (*)());
^------------------------+ (move left)
void (*(*somename)(void (*)()))(void (*)());
+-------------------------^ to function
void (*(*somename)(void (*)()))(void (*)());
+------------------------------------^ taking (void (*)())
void (*(*somename)(void (*)()))(void (*)());
^-----------------------------------------+ returning void
然后,您可以将规则应用于参数列表中的每个参数,从括号中的任何内容开始,因为在这种情况下我们没有标识符:
void (*)()
+^ pointer
void (*)()
^-+ (move left)
void (*)()
+--^ to function
void (*)()
^--------+ returning void
诀窍是使用顺时针螺旋规则http://c-faq.com/decl/spiral.anderson.html由于括号太多,这里有点困难,但是一旦你弄清楚它应该没问题。
此外,您还可以使用标签对复杂声明的一部分进行别名,并在理解其余部分后返回标签。 我的意思是:
void (*T)(void (*)());
你的 T 代替 ( somename)(void ( )())
C 语法允许各种事物的无限嵌套,因此解析声明可能需要多少内存没有限制。 解决这个问题:
void (*(*somename)(void (*)()))(void (*)())
,我们看到有函数参数,所以让我们将它们分开一点。void (*(*somename)(void (*)())) (void (*)())
。(*(*somename)(void (*)()))
是一个返回void
并接受类型为void (*)()
的参数的函数,它是一个指向没有原型的void
函数的指针.(*(*somename)(void (*)()))
。 左右括号匹配,所以这是*(*somename)(void (*)())
。void
函数取一个指向void
函数没有原型)。void
函数的指针。 因此, somename
指向一个函数:
void
函数的指针,并且void
函数的指针,该指针指向一个没有原型的void
函数。如果一个声明真的让你无法在没有帮助的情况下解析它,那么你可以构建一棵树来描述它。 C语法自然对应一棵树,学习相关理论和语法与解析之间的对应关系是计算机科学课程的一部分。 正如问题所问的那样,这对人类来说并不“有效”,但它是一种分析声明的确定性方法。
我开发的方法是从最左边的标识符开始计算,记住以下优先规则:
T *a[N]; // a is an array of pointer
T (*a)[N]; // a is a pointer to an array
T *f(); // f is a function returning a pointer
T (*f)(); // if is a pointer to a function
并对任何函数参数递归执行此操作。
我将使用 λ 来表示未命名的参数,因此我们得到如下结果:
somename -- somename is
*somename -- a pointer to
(*somename)( ) -- a function taking
(*somename)( λ ) -- unnamed parameter is
(*somename)( *λ ) -- a pointer to
(*somename)( (*λ)()) -- a function taking unspecified parameters
(*somename)(void (*λ)()) -- returning void
*(*somename)(void (*λ)()) -- returning a pointer to
(*(*somename)(void (*λ)()))( ) -- a function taking
(*(*somename)(void (*λ)()))( λ ) -- unnamed parameter is
(*(*somename)(void (*λ)()))( *λ ) -- a pointer to
(*(*somename)(void (*λ)()))( (*λ)()) -- a function taking unspecified parameters
(*(*somename)(void (*λ)()))(void (*λ)()) -- returning void
void (*(*somename)(void (*λ)()))(void (*λ)()); -- returning void
在英语中, somename
是一个指针,需要一个指向另一个函数作为参数,并返回一个指向另一个函数,它接受一个指向另一个函数作为它的参数和返回功能void
。
这种令人讨厌的类型在野外很少见,但它们偶尔会出现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.