顺时针/螺旋式规则 理解C/C++复杂定义

本文译自 spiral rule,后附全文.

顺时针/螺旋式规则

顺时针/螺旋式规则是一种能让任何C程序员理解程序声明的方法。
如下3个步骤:
1.从要确定类型的元素开始,按顺时针方向把下面遇到的元素替换为相应的语句,例如:
[X] or []
==>Array X size of ... or Array undefined size of ..;
(type1,type2)
==>function passing type1 and type2 returning...
*
==>pointer(s) to ...

2.一直以这种方式替换遇到的元素直到所有元素都被替换。
3.总是先处理小括号中的内容。

栗子
#1:简单声明
+-------+
| +-+ |
| ^ | |
char *str[10];
^ ^ | |
| +---+ |
+-----------+
先问自己:str是什么?
“str 是
a.我们以‘str‘开始,按顺时针方向,遇到的第一个符号是‘[‘,表明这是一个数组,所以:
‘str‘是一个包含10个XX的数组;(XX代表目前还未决定的)
b.继续以顺时针方向移动,下一个遇到的是‘*‘,说明这是一个指针,所以:
‘str‘是一个包含10个XX指针的数组;
c.继续顺时针方向移动,现在遇到了行尾的‘;‘,所以继续移动并且遇到了类型‘char‘,所以:
‘str‘是一个包含10个char指针的数组;

#2:函数指针声明
+--------------------+
| +---+ |
| |+-+| |
| |^ || |
char *(*fp)( int, float *);
^ ^ ^ || |
| | +--+| |
| +-----+ |
+------------------------+
先自问:fp是什么?
"fp是一个"
a.顺时针方向移动,我们遇到的第一个元素是‘)‘,因此,fp在内括号里,所以继续移动(在圆括号范围里,Rule NO 3),
遇到的下一个符号是‘*‘,所以:
fp是一个指向XX的指针;
b.跳出括号,继续以顺时针方向移动,遇到‘(‘,因此,这是一个函数,所以:
fp是指向一个返回XX的函数(函数的参数是int和float指针)的指针;
c.继续顺时针移动,遇到‘*‘符号,所以:
fp是指向一个返回XX指针的函数的指针;
d.继续顺时针移动,遇到‘;‘但是我们目前还没有访问到所有的元素,继续移动遇到类型‘char‘,所以:
fp是指向一个返回char指针的函数指针;

#3:"Ultimate"
+-----------------------------+
| +---+ |
| +---+ |+-+| |
| ^ | |^ || |
void (*signal(int, void (*fp)(int)))(int);
^ ^ | ^ ^ || |
| +------+ | +--+| |
| +--------+ |
+----------------------------------+

提问:‘signal‘是什么?
注意,‘signal‘是在括号内,所以要优先处理;
a.顺时针方向移动,遇到‘(‘,所以:
‘signal‘是一个函数(传递的参数是int和一个?)
b.哈哈,我们可以使用同样的规则来处理‘fp‘,同样的问题:‘fp‘是什么?由于‘fp‘也在一个括号内,继续移动看到‘*‘,
所以:
‘fp‘是一个指针;
b1.继续顺时针移动,遇到‘(‘,所以:
‘fp‘是一个指向函数(函数参数是int,返回XX)的指针;
b2.继续移动到括号外,遇到‘void‘;所以:
‘fp‘是一个指向函数(函数参数是int,返回为空)的指针;
‘c.fp的解析结束了,我们继续看‘signal‘,到现在为止我们知道:
‘signal‘是一个函数(参数是int和一个指向函数(函数参数是int,返回为空)的指针);
d.我们依然在括号中,所以遇到的下一个符号是‘*‘,所以:
‘signal‘是一个函数(参数是int和一个指向函数(函数参数是int,返回为空)的指针)返回指向XX的指针;
e.现在我们解决了括号内的所有元素,继续顺时针移动,我们遇到了另一个‘(‘,所以:
‘signal‘是一个函数(参数是int和一个指向函数(函数参数是int,返回为空)的指针)返回指向函数(参数是int,返回XX的函数)的指针;
f.最后,继续移动处理剩下的那个符号‘void‘,所以,最终的定义是:
‘signal‘是一个函数(参数是int和一个指向函数(函数参数是int,返回为空)的指针)返回指向函数(参数是int,返回为空的函数)的指针;

这个规则对于const和volatile(http://en.wikipedia.org/wiki/Volatile_(computer_programming))同样适用。
例如:
const char *chptr;
a.‘chptr‘是什么?
‘chptr‘是指向一个char常量的指针;
这个栗子:
char * const chptr;
a.chptr是什么?
‘chptr‘是指向char类型的常量指针;

最后的栗子:
volatile char * const chptr;
a.‘chptr‘是什么?
chptr是个‘char volatile‘的常量指针

[原文]
[This was posted to comp.lang.c by its author, David Anderson, on 1994-05-06.]
The ``Clockwise/Spiral Rule‘‘

By David Anderson

There is a technique known as the ``Clockwise/Spiral Rule‘‘ which enables any C programmer to parse in their head any C declaration!

There are three simple steps to follow:

Starting with the unknown element, move in a spiral/clockwise direction; when ecountering the following elements replace them with the corresponding english statements:
[X] or []
=> Array X size of... or Array undefined size of...
(type1, type2)
=> function passing type1 and type2 returning...
*
=> pointer(s) to...
Keep doing this in a spiral/clockwise direction until all tokens have been covered.
Always resolve anything in parenthesis first!
Example #1: Simple declaration

+-------+
| +-+ |
| ^ | |
char *str[10];
^ ^ | |
| +---+ |
+-----------+
Question we ask ourselves: What is str?
``str is an...
We move in a spiral clockwise direction starting with `str‘ and the first character we see is a `[‘ so, that means we have an array, so...
``str is an array 10 of...
Continue in a spiral clockwise direction, and the next thing we encounter is the `*‘ so, that means we have pointers, so...
``str is an array 10 of pointers to...
Continue in a spiral direction and we see the end of the line (the `;‘), so keep going and we get to the type `char‘, so...
``str is an array 10 of pointers to char‘‘
We have now ``visited‘‘ every token; therefore we are done!
Example #2: Pointer to Function declaration

+--------------------+
| +---+ |
| |+-+| |
| |^ || |
char *(*fp)( int, float *);
^ ^ ^ || |
| | +--+| |
| +-----+ |
+------------------------+
Question we ask ourselves: What is fp?
``fp is a...
Moving in a spiral clockwise direction, the first thing we see is a `)‘; therefore, fp is inside parenthesis, so we continue the spiral inside the parenthesis and the next character seen is the `*‘, so...
``fp is a pointer to...
We are now out of the parenthesis and continuing in a spiral clockwise direction, we see the `(‘; therefore, we have a function, so...
``fp is a pointer to a function passing an int and a pointer to float returning...
Continuing in a spiral fashion, we then see the `*‘ character, so...
``fp is a pointer to a function passing an int and a pointer to float returning a pointer to...
Continuing in a spiral fashion we see the `;‘, but we haven‘t visited all tokens, so we continue and finally get to the type `char‘, so...
``fp is a pointer to a function passing an int and a pointer to float returning a pointer to a char‘‘
Example #3: The ``Ultimate‘‘

+-----------------------------+
| +---+ |
| +---+ |+-+| |
| ^ | |^ || |
void (*signal(int, void (*fp)(int)))(int);
^ ^ | ^ ^ || |
| +------+ | +--+| |
| +--------+ |
+----------------------------------+
Question we ask ourselves: What is `signal‘?

Notice that signal is inside parenthesis, so we must resolve this first!

Moving in a clockwise direction we see `(‘ so we have...
``signal is a function passing an int and a...
Hmmm, we can use this same rule on `fp‘, so... What is fp? fp is also inside parenthesis so continuing we see an `*‘, so...
fp is a pointer to...
Continue in a spiral clockwise direction and we get to `(‘, so...
``fp is a pointer to a function passing int returning...‘‘
Now we continue out of the function parenthesis and we see void, so...
``fp is a pointer to a function passing int returning nothing (void)‘‘
We have finished with fp so let‘s catch up with `signal‘, we now have...
``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning...
We are still inside parenthesis so the next character seen is a `*‘, so...
``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to...
We have now resolved the items within parenthesis, so continuing clockwise, we then see another `(‘, so...
``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 returning...
Finally we continue and the only thing left is the word `void‘, so the final complete definition for signal is:
``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 returning nothing (void)‘‘
The same rule is applied for const and volatile. For Example:

const char *chptr;
Now, what is chptr??
``chptr is a pointer to a char constant‘‘
How about this one:

char * const chptr;
Now, what is chptr??
``chptr is a constant pointer to char‘‘
Finally:

volatile char * const chptr;
Now, what is chptr??
``chptr is a constant pointer to a char volatile.‘‘
Practice this rule with the examples found in K&R II on page 122.

Copyright © 1993,1994 David Anderson
This article may be freely distributed as long as the author‘s name and this notice are retained.

时间: 2024-10-09 18:07:22

顺时针/螺旋式规则 理解C/C++复杂定义的相关文章

关于DFS和BFS的理解 以及坐标的定义

1: 坐标类型搜索 :这种类型的搜索题目通常来说简单的比较简单,复杂的通常在边界的处理和情况的讨论方面会比较复杂,分析这类问题,我们首先要抓住题目的意思,看具体是怎么建立坐标系(特别重要), 然后仔细分析到搜索的每一个阶段是如何通过条件转移到下一个阶段的.确定每一次递归(对于DFS)的回溯和深入条件,对于BFS,要注意每一次入队的条件同时注意判重.要牢牢把握 目标状态是一个什么状态,在什么时候结束搜索.还有,DFS过程的参数如何设定,是带参数还是不带参数,带的话各个参数一定要保证能完全的表示一个

想了解概率图模型?你要先理解图论的基本定义与形式

图论一直是数学里十分重要的学科,其以图为研究对象,通常用来描述某些事物之间的某种特定关系.而在机器学习的世界里,我们希望从数据中挖掘出隐含信息或模型.因此,如果我们将图中的结点作为随机变量,连接作为相关性关系,那么我们就能构造出图模型,并期望解决这一问题.本文将为构造该模型提供最基础的概念. 我们都知道机器学习里的决策树,其可以表示为给定特征条件下类的条件概率分布.并且我们知道决策树由结点和有向边组成,结点又由表示特征的内部结点和表示类的叶结点构成.而通常决策树的学习又包括了特征的选择.决策树的

[译] 理解PHP内部函数的定义(给PHP开发者的PHP源码-第二部分)

文章来自:http://www.aintnot.com/2016/02/10/understanding-phps-internal-function-definitions-ch 原文:https://nikic.github.io/2012/03/16/Understanding-PHPs-internal-function-definitions.html 欢迎来到"给PHP开发者的PHP源码"系列的第二部分. 在上一篇中,ircmaxell说明了你可以在哪里找到PHP的源码,它

深入理解无穷级数和的定义(the sum of the series)

Given an infinite sequence (a1, a2, a3, ...), a series is informally the form of adding all those terms together: a1 + a2 + a3 + ···. To emphasize that there are an infinite number of terms, a series is often called an infinite series. 值得注意的是等式右边并不是左

Path类的最全面具体解释 - 自己定义View应用系列

前言 自己定义View是Android开发人员必须了解的基础:而Path类的使用在自己定义View绘制中发挥着很关键的数据 网上有大量关于自己定义View中Path类的文章.但存在一些问题:内容不全.思路不清晰.简单问题复杂化等等 今天.我将全面总结自己定义View中Path类的使用,我能保证这是市面上的最全面.最清晰.最易懂的 文章较长,建议收藏等充足时间再进行阅读 阅读本文前请先阅读自己定义View基础 - 最易懂的自己定义View原理系列 文件夹 1. 简单介绍 定义:路径.即无数个点连起

[转载]c语言宏定义

一. #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能理解该命令的本质,总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时,把运行结果理解错误,这对 C语言的学习很不利. 1 #define命令剖析 1.1   #define的概念 #define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为

Apache Commons Digester 二(规则模块绑定-RulesModule、异步解析-asyncParse、xml变量Substitutor、带参构造方法)

前言 上一篇对Digester做了基本介绍,也已经了解了Digester的基本使用方法,接下来将继续学习其相关特性,本篇主要涉及以下几个内容: 规则模块绑定,通过定义一个RulesModule接口实现类来完成规则的预先绑定,运行时重复使用 异步解析xml 解析xml中的变量,如${sys.user} 使用带参数的构造方法创建对象,参数来自xml节点数据 规则模块预先绑定 - RulesModule接口 在此之前,我们使用Digester的基本流程都是每次在程序运行时绑定规则,然后解析: 事实上,

非规则浮点数和规则浮点数

本文由量化.数据类型.上溢和下溢衍生,将浮点数看作是实数域的一种量化方式,分析浮点数,尤其是非规则浮点数和规则浮点数之间的差异. 0. 背景.动机和目的 为了更好理解本文内容,可先行阅读<量化.数据类型.上溢和下溢>中内容.这里依旧将浮点数看作是一种量化方式,将连续的不可数的集合映射到有限的集合上去.本文结合单精度浮点数讨论,双精度浮点与之类似. 已有多位博主撰写过关于非规则浮点数(Denormalized Number)和规则浮点数之间的区别,这里首推卢钧轶的你应该知道的浮点数基础知识.这篇

深入理解mysql之BDB系列(1)---BDB相关基础知识

    深入理解mysql之BDB系列(1) ---BDB相关基础知识 作者:杨万富 一:BDB体系结构 1.1.BDB体系结构 BDB总体的体系结构如图1.1所看到的,包括五个子系统(见图1.1中相关数).1)数据存取子系统,2)事务子系统,3)锁子系统,4)内存池管理子系统,5)日志子系统. 在一个应用程序中,并不一定须要全然具备这5大子系统. 假设程序仅仅使用了数据存取子系统,它的体系结构如图1.2.在图1.2中,我们仅仅使了两个子系统:数据存取以及内存池子系统.(备注:另外三个子系统在B