目录
引言
基本的C语言声明
较复杂的C语言声明
没有最复杂,只有更复杂
C语言声明的分析法则
分析法则的运用
结束语
参考文献
引言
C语言常常因为声明的语法而收到人们的批评,特别是涉及到函数指针的用法。对于简单的情况,C语言的做法是很有效的,但是,如果情况比较复杂,则容易让人混淆,原因在于,C语言的声明不能从左至右阅读,而且使用了太多的圆括号。
本文旨在总结自己在分析C语言声明方面的学习心得,并与大家交流C语言声明的一般分析方法,希望能够帮助大家攻克理解C语言声明的难关。本文首先从简到繁地列出C语言中的各种声明,然后给出C语言声明的分析法则,最后通过一些实例讲解该分析法则的实际运用。
基本的C语言声明
1、int a;
a为常规变量,该变量具有int类型
2、int a[2];
a为数组,该数组包含2个int变量
3、int *p;
p为指针,该指针指向一个int变量
4、int f();
f为函数,该函数无参数且返回一个int变量
5、struct person { char *name, int height, int weight; };
struct person a;
a为结构体变量
6、union bits32
{
int whole;
struct { char c0, c1, c2, c3; } byte;
};
union bits32 a;
a为联合体变量
7、enum fruit {apple=8, pear, orange=12, banana};
enum fruit a;
a为枚举变量
较复杂的C语言声明
1、int *a[2];
a为数组,该数组包含2个指向int的指针
int (*a)[2];
a为指针,该指针指向一个数组,该数组包含2个int
2、const int *p;
p为指针,该指针指向一个只读int
int const *p;
同上
int * const p;
p为只读指针,该指针指向一个int
const int * const p;
p为只读指针,该指针指向一个只读int
int const * const p;
同上
3、int **p;
p为指针,该指针指向一个对象,该对象为指向int的指针
int * const *p;
p为指针,该指针指向一个对象,该对象为指向int的只读指针
4、int *f();
f为函数,该函数无参数且返回一个指向int的指针
int (*f)();
f为指针,该指针指向一个函数,该函数无参数且返回一个int
没有最复杂,只有更复杂
下面的声明,你能读懂几个?
1、int (*func)(int *p, int (*f)(int*));
2、int (*func[5])(int *p);
3、int (*(*func)[5])(int *p);
4、int (*(*func)(int *p))[5];
5、int func()();
6、int func()[5];
7、int func[5]();
C语言声明的分析法则
C语言声明的分析法则,可以表达为如下几个步骤:
1、从左到右找到第1个标识符tag
2、查看tag右边的下一个符号:
如果是“[”,即形如“tag[N]”,则tag为一个数组;(其中,N为数组大小)
如果是“(”,即形如“tag(…)”,则tag为一个函数。(其中,…为函数参数)
以上两种情况,跳到4
3、查看tag左边的上 一个符号:
如果是 “*”,即形如“*tag”,则tag为一个指针
如果是类型名称,如“int tag”,则tag为一个常规变量,跳到5
4、判断tag的 性质:
如果是 数组,在tag的声明字符串中,用“tag1”替换“tag[N]”,则数组tag中的元素为tag1;
如果是函数,在tag的声明字符串中,用“tag1”替换“tag(…)”,则函数tag的返回值为tag1;
如果是指针,在tag的声明字符串中,用“tag1”替换“*tag”(或者更常见的“(*tag)”),则指针tag所指向的对象为tag1
(注意:若tag1的声明较复杂,则跳到2分析tag1 ;
若被tag1替换的部分或tag1本身为函数,且其中的某个参数par的声明较复杂,则跳到2分析par
)
5、结束
分析法则的运用
在“没有最复杂,只有更复杂”一节,我们列出了一些非常复杂的C语言声明,其中不少声明源自网上一些朋友的文章中的例子。那些声明尽管在实际中很少遇到,但对它们的研究非常有助于我们掌握C语言声明的分析方法。对于那些复杂声明,如果在那时你觉得束手无策、摸不着边,那么此刻在给出了“C语言声明的分析法则”之后,你就应该能够有章可循、从容不迫了。
下面我们将运用“C语言声明的分析法则”,逐一对那些复杂的C语言声明进行分析理解:
1、int (*func)(int *p, int (*f)(int*));
标识符:func
右边:( ,左边:*
因此func是一个指针,用a替换(*func),则func指向a对象
a的声明:int a(int *p, int (*f)(int *));较简单
a为一个函数,该函数的第2个参数f较复杂,分析标识符f
使用分析法则,得出f为一个函数指针
结论:func是一个函数指针,它指向的函数返回int,且以p和f为参数。其中p为int指针;f为另一个函数指针,该函数返回int,以一个int指针为参数。
2、int (*func[5])(int *p);
标识符:func
右边:[
因此func是一个数组,用a替换func[5],则func中有5个a
a的声明:int (*a)(int *p);较复杂,分析标识符a
使用分析法则,得出a为一个函数指针
结论:func是一个数组,其中有5个元素,每个元素都是函数指针。函数指针指向的函数返回int,且以一个int指针p为参数。
3、int (*(*func)[5])(int *p);
结论:func是一个数组指针,它指向的数组具有5个元素,每个元素都是函数指针。该函数指针指向的函数返回int,且以一个int指针p为参数。
4、int (*(*func)(int *p))[5];
结论:func是一个函数指针,它指向的函数以int指针为参数,且返回一个数组指针。该数组指针指向的数组具有5个元素,每个元素都是int。
5、int func()();
func是一个函数,它返回一个函数。返回的函数无参数,且返回一个int
非法:在C语言中,函数的返回值不能是一个函数!
6、int func()[5];
func是一个函数,它返回一个具有5个int的数组
非法:在C语言中,函数的返回值不能是一个数组!
7、int func[5]();
func是一个具有5个元素的数组,每个元素都是一个函数,该函数无参数,且返回一个int
非法:在C语言中,数组里面不能有函数!
由上面的分析实例可以看出,不管是合法的C语言声明,还是非法的C语言声明,其分析法则都是一致的。非法的C语言声明只是不满足语法要求而已。C语法对声明的合法性有限制,但C语言声明的分析法则却没有限制。由此可见,“C语言声明的分析法则”一节中给出的分析法则是一种通用法则,对于C语言中的任何声明,不管是简单的C语言声明(大家对于简单的C语言声明多是根据平时的记忆积累来判断的,不妨用我们的分析规则来分析理解一下,定能加深你对一些常见简单的C语言声明的认识),还是复杂的C语言声明,都可以用该法则来进行分析理解。当然,只有对合法的C语言声明进行分析才是有意义的:-)
结束语
通过上面的讲解,我相信大家对C语言声明一定有了更深的认识,对于分析简单或复杂的C语言声明也一定有了更多的把握。
学习贵在总结、分享与交流。这篇文章是我学习C语言声明分析的阶段性总结;如果本文能够给大家带来启发和帮助,那我花一下午的时间来打字和排版就更值得了;当然,本人能力有限,如果有阐述不清、描述不当甚至观点有误的地方,还请大家给予批评指正。
参考文献
《C专家编程》
《C程序设计语言》(第2版·新版)