The “Clockwise/Spiral Rule”
By David Anderson
每个C程序员在脑袋里解析任何C声明的时候都会用到一种技术——顺时针/螺旋规则!
该规则只有简单的3步:
从未知元素开始,沿顺时针/螺旋方向移动;当遇到如下元素的时候,用相应的自然语言陈述出来:
- [X] 或者 [] => 大小为…的数组X 或 未知大小数组的…(Array X size of… or Array undefined size of…)
- (type1, type2) => 传入type1和type2参数、返回…的函数(function passing type1 and type2 returning…)
- * => 指向…的指针(pointer(s) to…)
一直沿着顺时针往下进行,直到覆盖了所有的元素。
括号内的永远优先!
其实对英文来说就是不断在后边加定语,但对汉语来说,就需要不断在前边加定语。
1.简单声明
+-------+
| +-+ |
| ^ | |
char *str[10];
^ ^ | |
| +---+ |
+-----------+
首先需要问的是:str
是什么?
str 是个…(str is an…)
- 我们从
str
开始顺时针移动,碰到的第一个元素是[
,这意味着我们碰到了个数组,于是就有…str是个大小是10、…的数组(str is an array 10 of…)
- 继续顺时针,下一个遇到的是
*
,这意味着我们碰到了个指针,就有…str是个大小是10、指向…指针的数组(str is an array 10 of pointers to…)
- 继续,下一个是该行结尾
;
;继续,接下来是char
,因此…str是个大小是10、指向字符的指针的数组(str is an array 10 of pointers to char)
2.指向函数的指针的声明
+--------------------+
| +---+ |
| |+-+| |
| |^ || |
char *(*fp)( int, float *);
^ ^ ^ || |
| | +--+| |
| +-----+ |
+------------------------+
还是一样,首先要问:fp
是什么?
fp 是个…(fp is a…)
- 顺时针移动,首先看到了
)
,因此fp
就在括号中了,我们在括号中顺时针移动,下一个看到的是*
,因此…fp 是个指向…的指针(fp is a pointer to…)
- 跳出括号,继续顺时针转动,看到了
(
,这表明遇到了一个函数,就有…fp 是个指向传入参数是int和指向float的指针、返回值是…的函数的指针(fp is a pointer to a function passing an int and a pointer to float returning…)
- 继续顺时针,看到了
*
,说明…fp 是个指向传入参数是int和指向float的指针、返回值是指向…的指针的函数的指针(fp is a pointer to a funciton passing an int and a pointer to float returning a pointer to…)
- 继续,遇到
;
;再继续,遇到了char
,因此…fp 是个指向传入参数是int和指向float的指针、返回值是指向char的指针的函数的指针(fp is a pointer to a function passing an int and a pointer to float returning a pointer to a char)
3.终极形态
+-----------------------------+
| +---+ |
| +---+ |+-+| |
| ^ | |^ || |
void (*signal(int, void (*fp)(int)))(int);
^ ^ | ^ ^ || |
| +------+ | +--+| |
| +--------+ |
+----------------------------------+
依然是:signal
是什么?
注意signal
在括号中,需要先解决它
- 顺时针移动,首先遇到
(
,因此…signal是个传入参数为int和…,返回…的函数(signal is a function passing an int and a…)
- 接着,我们可以对
fp
用相同的规则,fp
是什么?fp
在括号中,首先遇到的是*
,于是…fp是个指向…的指针(fp is a pointer to…)
- 继续会遇到
(
,就有…fp是个指向传入参数是int、返回…的函数的指针(fp is a pointer to a function passing int returning…)
- 接着,看到了
void
…fp 是个指向传入参数是int、返回值为空(void)的函数的指针(fp is a pointer to a function passing int returning nothing (void))
- 现在结束了对
fp
的解析,接着看signal
…signal是个传入参数为int和指向传入参数为int、返回值为空的函数的指针,返回值为…的函数(signal is a function passing an int and a pointer to a function passing an int returning nothing(void) returning…)
- 现在还在括号内,接着的元素是
*
…signal是个传入参数为int和指向传入参数为int、返回值为空的函数的指针,返回值为指向…的指针的函数(signal is a function passing an int and a pointer to a funciton passing an int returning nothing(void) returning a pointer to…)
- 再继续,碰到了
(
…signal是个传入参数为int何指向传入参数为int、返回值为空的函数的指针,返回值为指向一个传入参数为int、返回值为…的函数的指针的指针的函数(signal is a function passing an int and a pointer to a function passing an int returning nothing(void) returning a pointer to a function passing an int and returning…)
- 终于到最后了,我们只剩下
void
这一个元素了,最终signale
的定义为…signal是个传入参数为int何指向传入参数为int、返回值为空的函数的指针,返回值为指向一个传入参数为int、返回值为空的函数的指针的指针的函数(signal is a function passing an int and a pointer to a function passing an int returning nothing(void) returning a pointer to a function passing an int and returning nothing(void))
const
和volatile
的例子
规则一样的
1 | const char *chptr: |
chptr
是个指向一个char常量(constant)的指针(chptr is a pointer to a char constant)
1 | char * const chptr; |
chptr
是个指向char的常量指针(chptr is a constant pointer to char)
1 | volatile char * const chptr; |
chptr
是个指向一个char原子(volatile)的常量指针(chptr is a constant pointer to a char volatile)
C的复杂声明其实就不断加定语,但是这个定语在修饰的是哪个主语,需要按照顺时针/螺旋规则来解释。熟悉了就好。