C语言声明的螺旋法则
C语言声明的螺旋法则
最近在B站看到了“顺时针/螺旋法则”(Clockwise/Spiral Rule),又称螺旋法则,这一法则主要用于解析C语言中的复杂声明,而平时接触的复杂声明莫过于变幻莫测的指针,尤其是那些函数指针。法则的内容十分简单,它将声明解析分为了三个步骤:
Starting with the unknown element, move in a spiral/clockwise direction; when ecountering the following elements replace them with the corresponding english statements:
从未知变量开始,按顺时针螺旋顺序阅读,当遇到以下元素替换为相应的自然语言表达:
[ ] or [] => Array X size of… or Array undefined size of…
=> 长度为X或者长度未知的……类型数组(type1, type2) => function passing type1 and type2 returning…
=> 传入参数类型为type1和type2、返回值类型为……的函数* => pointer(s) to…
=> 指向……类型的指针
Keep doing this in a spiral/clockwise direction until all tokens have been covered. 重复顺时针螺旋法则直到读完所有元素。
Always resolve anything in parenthesis first! 优先处理括号内内容!
应用上述法则,可以尝试处理以下声明:
1 |
|
应用顺时针/螺旋法则解读这类复杂声明不仅简单有效,而且由来已久,早在1994年就有人提出。一般具体使用时,会用 typedef 语法替代复杂的指针声明,提高代码的可读性,C++11中 using 也有等效于 typedef 的用法,一定程度解决了C语言 typedef 不兼容C++ template 的问题,例如下面的代码:
1 |
|
关于这种声明,Ptr类型的解读就非常微妙,《C陷阱与缺陷》有一个类似的例子—— (*(void(*)())0)(),这个例子是的作用是在计算机开机时由硬件显式调用首地址为0的子例程。虽然看上去比较复杂,但C语言的声明都存在 [type declarator] 结构,如果我们对前面的代码进行分析,可以得出以下结构:
1 |
|
对照 (*(void(*)())0)() 和上述typedef应该可以发现,void(*)() 似乎和 int (*)() 类似,假设我们称 void(*)() 类型为PF(aka. typedef void(*)() PF;),那么原式应该为 (*(PF)0)(),于是我们可以发现 (PF)0 似乎是将0转化为PF类型,假设 PF pf = (PF)0,那么原式就等于 (*pf)()。回想我们对于函数的定义和调用,int main(); 的调用方法就是 main();,那么在这里同理 (*pf)() 实际上也是调用了定义为 type_unknown (*pf)(); 的函数。回过头思考前面那个声明,Ptr 实际上也是上述typedef的同类,关键还是知道未知变量declaration原来在typdef的哪里,了解清楚这一要点,可以将原式转化为以下内容:
1 | // Ptr 是指向接受type1和type2参数、返回值为int类型的函数的指针 |