右左法则是一个既著名又常用的方法。不过,右左法则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的。
右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。
要理解比较复杂的指针类型声明,在描述一个指针时就要注意语言比较简明。下面是我的一些规则。
描述一个数组时:int a[5] a是一个且有5个元素的数组,它的元素是int型变量
描述一个函数指针时:int (*p)(int i) p是一个函数指针,这类函数且有int型返回值,且有一个int型参数
int (*func)(int *p);
。从func看起,向左到括号,向右为*,结果:func为一个指针
。跳出括号,向右看,又是一个括号。结果:func为一个指针函数
。向左为int 结果:func为一个函数指针,这类函数且有一个int*型参数,且有一个int型返回值。
int (*func)(int *p, int (*f)(int*));
。从func看起,向左到括号,向右为*,结果:func为一个指针
。跳出括号,向右看,又是一个括号。结果:func为一个指针函数
。向左为int 结果:func为一个函数指针,这类函数且有一个int (*f)(int*)参数,且有一个int型返回值。
。第二个参数较复杂,单独来看,可以发现与上面的例子一样。
int (*func[5])(int *p);
。从func看起,向左为[5],结果:func为一个且有5个元素的数组。
。向右为*,结果:数组的元素为指针
。跳出括号,向右看,又是一个括号。结果:数组的元素是一个指针数组
。向左为int 结果:func是一个且有5个元素的数组,数组的元素为一个函数指针,这类函数且有int型返回值,且有一个int*型参数。
说明:因为第一次向右看即为数组,说明func是数组,这里已经固定func的类型,下面再说即是对数组元素的描述
int (*(*func)[5])(int *p);
。从func看起,向左到括号,向右为*,结果:func为一个指针
。跳出括号,向右看,是一个[5],说明func是一个数组指针,指向一个且有5个元素的数组。
。向左看,是一个*,说明数组的元素是指针。
。跳出括号,向右看,是一个括号,说明数组的元素是函数指针
。向左为int 结果:func为一个指向且有5个元素的数组的指针,数组的元素是一个函数指针,这类函数且有int型返回值,且有一个int*型参 数
说明:这里从指针跳到数组元素,再从数组元素跳到函数指针,一层层的说明。更容易理清条理
int (*(*func)(int *p))[5];
。从func看起,向右为括号,向左为*,说明func是一个指针
。跳出括号向右为一个括号,说明func是一个函数指针,这类函数且有int*型参数
。向左为一个*,说明这类函数返回指为一个指针
。向右为[5],说明这类函数返回值为数组指针
。向左为一个int,说明数组且有5个int型元素
。func是一个函数指针,这类函数且有一个int*型参数。返回值为数组指针,数组里有5个int型元素
说明:当确定为数组后,马上进入数组元素的分析
当确定为函数指针后,马上进入对函数的分析,函数类型、函数返回值
当确定为数组指针后,马上进入它所指向数组的分析
实际应用中这样声明复杂的类型大大影响程序的可读性。应该分解,比如:
int (*(*func)(int *p))[5];
可以分解为:
typedef int (*PARA)[5];
PARA (*func)(int *p);
本文介绍了C语言中用于解析复杂声明的右左法则,并通过具体示例详细解释了如何使用该法则来理解指针、数组及函数指针等类型的声明。
657





