· updated Apr 03, 2022 · 7 min read
笔记:使用 Clockwise/Spiral Rule 技巧轻松读懂变量/函数声明
本文介绍一种让编程者很方便搞清楚C/C++变量或者函数声明的小技巧Clockwise/Spiral Rule,本文很大部分内容参考自 David Anderson 于 1994 年 05 月 06 日写的一篇博客。
规则
Step 1. 从未知的变量开始,以“螺旋状+顺时针”方向移动,当遇到以下内容时,请用相应的英文语句来代替它们:
[X] or []
=> Array X size of... or Array undefined size of...
(type1, type2)
=> function passing type1 and type2 returning...
*
=> pointer(s) to...
Step 2. 重复步骤 1,直到所有的符号都被遍历;
Step 3. 一定要先解决括号里的东西!
例 1:简单声明
+-------+
| +-+ |
| ^ | |
char *str[10];
^ ^ | |
| +---+ |
+-----------+
首先问自己的一个问题:str是什么玩意?
str is an …
-
我们从
str开始,以螺旋式顺时针方向移动,我们看到的第一个字符是[,所以,这意味着这里有一个数组,所以……str is an array 10 of…
-
继续以螺旋式的顺时针方向前进,我们遇到的下一符号是
*,所以,这意味着这里有个指针,所以……str is an array 10 of pointers to…
-
继续沿螺旋方向前进,我们看到了行的末端(
;),所以继续前进,得到了char类型,所以……str is an array 10 of pointers to char
-
现在已经访问了每一个符号,搞定!
例 2:指向函数声明的指针
+--------------------+
| +---+ |
| |+-+| |
| |^ || |
char *(*fp)( int, float *);
^ ^ ^ || |
| | +--+| |
| +-----+ |
+------------------------+
首先问自己的一个问题:fp是什么玩意?
fp is a …
-
我们从
fp开始,以螺旋式顺时针方向移动,我们看到的第一个字符是),因此fp在括号内,所以我们在括号内继续螺旋式移动,看到的下一个字符是*,所以……fp is a pointer to…
-
我们离开了小括号,继续以螺旋式顺时针方向前进,我们看到了
(;因此,我们有一个函数,所以……fp is a pointer to a function passing an int and a pointer to float returning…
-
继续以螺旋方式进行,然后我们看到
*字符,所以……fp is a pointer to a function passing an int and a pointer to float returning a pointer to
-
以螺旋的方式继续,我们看到了
;,但还没有访问所有的符号,所以继续,最后到了char类型,所以……fp is a pointer to a function passing an int and a pointer to float returning a pointer to char
-
现在已经访问了每一个符号,搞定!
例 3:终极挑战!
+-----------------------------+
| +---+ |
| +---+ |+-+| |
| ^ | |^ || |
void (*signal(int, void (*fp)(int)))(int);
^ ^ | ^ ^ || |
| +------+ | +--+| |
| +--------+ |
+----------------------------------+
首先问自己的一个问题:signal是什么玩意?(注意,变量signal在括号内,所以我们必须先搞定它)
signal is a …
-
沿着顺时针方向移动,我们看到
(,所以我们有……signal is a function passing an int and a …
-
额,函数传参的第二个变量有点复杂;那我们可以对
fp使用同样的规则,所以……fp 是什么玩意?fp也在小括号内,所以继续我们看到一个*,所以……fp is a pointer to…
-
继续沿顺时针方向螺旋上升,我们得到了
(,所以知道遇到了函数……fp is a pointer to a function passing int returning…
-
现在继续走出函数的小括号,我们看到了
void,所以……fp is a pointer to a function passing int returning nothing(void)
-
我们已经完成了解析 fp,所以让我们继续解析
signal,我们现在有……signal is a function passing an int and a pointer to a function passing int returning nothing(void)
-
注意到我们仍然在括号内,所以看到的下一个字符是
*,所以……signal is a function passing an int and a pointer to a function passing int returning nothing returning a pointer to…
-
我们现在已经解决了括号内的符号,所以继续按顺时针方向,我们看到另一个
(,我们知道遇到了函数,所以……signal is a function passing an int and a pointer to a function passing int returning nothing returning a pointer to a function passing int returning…
-
最后我们继续,唯一剩下的就是
void,所以signal的最终完整定义是……signal is a function passing an int and a pointer to a function passing int returning nothing returning a pointer to a function passing int returning nothing(void)
-
现在已经访问了每一个符号,搞定!
其它
这个规则同样适用于const 以及 volatile,例如:
const char *ptr;
ptr is a pointer to a char constant(ptr 是指向 const char 的指针,即 ptr 指向的值不可改变,但是指针可以改变)
char const *ptr;
ptr is a pointer to a constant char
所以 const char *ptr 与 char const * ptr表示一个意思。
char * const ptr;
ptr is a constant pointer to char(ptr 是一个 const 指针指向 char,即 ptr 不可改变,但是指针指向的内容可以改变)
volatile char * const ptr;
ptr is a constant pointer to char volatile
参考
- David Anderson, Clockwise/Spiral Rule, http://c-faq.com/decl/spiral.anderson.html, 1994.
- stackoverflow, What is the difference between const int*, const int* const, and int const *?