作者:杨硕,华清远见嵌入式学院讲师。
C语言的设计哲学要求对象的声明形式和它的使用形式尽可能相似,比如一个int类型的指针数组被声明为int *p[3];并以*p这样的表达式引用或者使用指针所指向的int数据,所以它的声明形式和使用形式非常相似。这样做的好处是各种不同操作符的优先级在“声明”和“使用”时是一样的,而缺点恰好在与C语言的操作符的优先级过于复杂(有15级或者更多,取决于你怎么算),这是C语言设计不当、过于复杂之处。
实际上有些关键字只能出现在声明中,而不是使用中,比如volatile和const等,这使得声明形式和使用形式能完全对的上号的例子越来越少了。如果想要把什么东西强制转换为指向数组的指针,就不得不使用下面的语句来表示这个强制类型转换:
———char (*j) [ 20 ];
———j = ( char ( * )[20] ) malloc(20);
这个强制类型转换看上去很滑稽,星号两边的括号看上去可有可无,但是如果去掉就会变成非法语句。
涉及指针和const得声明可能会有下面几种不同的组合:
———const int * p;
———int const * p;
———int * const p;
前两种情况,指针所指向的对象是只读的,而最后一种情况下指针是只读的。
如果我们想让对象和指针都是只读的,那么下面两种声明都能做到这一点:
———const int * const p;
———int const * const p;
经过初级篇、中级篇一直到前面的学习我们发现其实分析一个声明就是按照操作符优先级规则把声明分解开来,分别解释各个组成部分。要理解一个声明,必须要懂得其中的优先级规则,下面是《C专家编程》中总结的C语言声明的优先级规则:
A声明从它的名字开始读取,然后按照优先级顺序依次读取;
B 优先级从高到低依次是:
B.1 声明中被括号括起来的那部分;
B.2 后缀操作符:括号()表示这是一个函数,而方括号[]表示这是一个数组;
B.3 前缀操作符:星号*标识“指向……的指针”;
C 如果const和(或者)volatile关键字的后面紧跟类型说明符(如int,long等),那么它作用于类型说明符,在其他情况下,const和(或)volatile关键字作用于它左边紧邻的指针星号。
现在,让我们用优先级规则来分析C语言的一个较复杂的声明:
———char * const *(*next) ();
B.1 (*next) ——next为一个指向……的指针
B.2 (*next)() ——next是一个函数指针
B.3 *(*next)() ——next是一个函数指针,这个函数返回一个指向……的指针
C char * const ——指向字符类型的常量指针
故 char * const *(*next)();的含义就是:next是一个函数指针,这个函数返回一个指向字符类型的常量指针。
我想到现在我们是不是发现分析C语言声明其实并不像一开始那么令人感到无比痛苦,它反而给我们带来了乐趣,不是吗?其实我们只要多分析几个实例,多读一些高质量的C代码,那么分析一个C语言声明不再是一件可怕的事情(更何况我们还有cdecl这个强大的声明解释器呢,呵呵!),这匹野马一旦被我们驯服了,那么它将帮助我们编写出高质量的C代码。你准备好了吗?
文章评论(0条评论)
登录后参与讨论