📝笔记:使用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) -
现在已经访问了每一个符号,搞定! d ## 其它
这个规则同样适用于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 *?