这就是 C 语法的工作原理。 Block 语法基于 function pointers 的语法,这归结为 Dennis Ritchie 的想法,即“事物的声明应该看起来像对该事物的使用”。
如果你要使用你定义的“复杂块”,然后在同一行中调用返回的块,它看起来像这样:
complexBlock(void (^argBlock)(void){ /*...*/ })();
// ^ Argument (a literal Block) to the main Block
// ^ Invocation of the returned Block
此外,C 声明的解析遵循所谓的"right-left rule"。第一步是“找到标识符”。对于你的声明,那是complexBlock。
void (^(^complexBlock)(void (^)(void)))(void);
// | ! | Found identifier: "complexBlock is..."
然后,向右看。我们点击了右括号,所以这是声明“单元”的结尾。
void (^(^ )(void (^)(void)))(void);
// | ! Right parenthesis closes a part of the declaration
回到当前部分的开头,向左阅读直到一个左括号。我们找到指示块类型的插入符号。继续往左看,找到一个左括号,结束声明的这一部分。
void (^(^ (void (^)(void)))(void);
// |! | "...a Block..."
接下来,再向右走。在这里,我们找到一个左括号,表示参数列表的开始。跳过参数列表,因为您关心返回类型,但它被解析为独立声明。
void (^ (void (^)(void)))(void);
// | ! | "...taking something or other and returning..."
现在我们已经使用了参数列表:
void (^ )(void);
// | |
继续向右移动,我们找到了一个右括号:
void (^ )(void);
// | !
所以,再次回到当前部分的开头并向左移动我们找到块插入符号的位置。
void (^ (void);
// ! | "...a Block.."
以下是您关于此声明的问题的关键部分:
向左移动,我们再次找到一个左括号,所以我们返回向右移动。这就是为什么 return Block 的参数列表放在声明的末尾。
void ( (void);
// ! | Left parenthesis closes part of declaration,
// **now move rightwards again**
经历了所有这些,其余的应该是不言而喻的。
顺便说一下,我链接到的关于左右规则的页面有一些和我一样的演示,其中一个涉及函数指针。您可能还会对http://cdecl.org 感兴趣,这是一个在线实现的程序,可以解析 C 声明,可以帮助您了解更羊毛的品种。