您的位置:首页 > 编程语言 > C语言/C++

[C专家]分析C语言声明——声明是如何形成的[1]

2017-08-12 19:38 399 查看
让我们先来看一些C语言的术语以及一些能组合成一个声明的单独语法成分。其中一个非常重要的成分就是声明器(declarator)——它是所有声明的核心。简单地说,声明器就是标识符以及与它组合在一起的任何指针、函数括号、数组下标等,如下表所示。为了方便起见,我们把初始化内容(initializer)也放到里面,并分类表示。

声明器



注:上表中* const volatile、* volatile、* const、* volatile const,这里的const和volatile是用于限定指针的。

一个声明由下表所示的各个部分组成(并非所有的组合形式都是合法的,但这个表描述了我们进一步讨论所要用到的词汇)。声明确定了变量的基本类型以及初始化值(如果有的话)。

声明说明符



注:这里的类型限定符const和volatile是用于限定类型说明符指定的类型,与上面* const volatie等是不一样的。

注:上表中倒数第二行“零个或多个声明器”的意思是,举例来说就是一次声明多个:static const int i,j,k,l,m.n;,这里的j、k、l、m、n就属于倒数第二行中提到的。而这里的i就是倒数第三行中提到的。

注:const static int * const p(); 

const、static、int 属于声明说明符;* const、p()属于声明器

p是一个函数,它返回一个指针,这个指针是只读的,这个指针指向一个int类型的对象,并且该对象也是只读的,最后这个函数只能在声明所在的文件内可见。

声明说明符:声明说明符是以嵌套形式组织的,以上为例有三个声明说明符const、static、int。

const是一个类型说明符,它后面的声明说明符是static int;

static是一个存储说明符,它后面的声明说明符是int;

int是一个类型说明符,它后就就是声明器,已经没有嵌套了

对于声明说明符的排列顺序,C标准并没有规定,谁嵌套谁都可以,所以static const int、int static const 、int const static 都是一个意思。

让我们看一下如果你使用这些部件来构造一个声明,情况能够复杂到什么程度。同时要记住,在合法的声明中存在限制条件。你不可以像下面那样做:

函数的返回值不能是一个函数,所以像foo()()这样是非法的
函数的返回值不能是一个数组,所以像foo()[]这样是非法的
数组里面不能有函数,所以像foo[]()这样是非法的

但像下面这样则是合法的:

函数的返回值允许是一个函数指针,如: int (*fun())()
函数的返回值允许是一个指向数组的指针,如:int (* foo())[]
数组里面允许有函数指针,如:int (* foo[])()
数组里面允许有其它数组,如:int foo[][]

扩展

C标准中的“右左法则”是用来辨识一个声明的方法,其具体流程如下:

首先从未定义的标识符开始,然后往右看,再往左看。每当遇到圆括号时,就应该调转阅读方向。一旦解析完圆括号里面所有东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。

例1:int (*func)(int *p);

首先找到未定义标识符func,它的外面有一对圆括号,而且它的左边有一个*,所以func是一个指针;

跳出这个圆括号,看右边,也是一个圆括号,说明(*func)是一个函数,而func是一个指向函数的指针,这类函数有一个int *类型的形参;

跳出这个圆括号,看左边,是一个int,说明这类函数返回的是一个int类型的值

例2:int (*func)(int *p, int (*f)(int *));

未定义标识符func,它外面有一对圆括号,而且它的左边有一个*,所以func是一个指针;

跳出这个圆括号,看右边,也是一个圆括号,说明(*func)是一个函数,而func是一个指向函数的指针,这类函数具有int * 和 int (*)(int *)这样的形参;

跳出这个圆括号,看左边,是一个Int,说明这类函数返回的是一个int类型的值。

例3:int (*func[5])(int *p);

未定义标识符func,看右边,有一对方括号,说明它是一个具有5个元素的数组;

看左边,是一个*,说明数组的元素是指针;

跳出这个圆括号,看右边,也是一对圆括号,说明数组中的元素是函数指针,这类函数具有int *这样的形参;

跳出这个圆括号,看左边,是一个int,说明这类函数返回的是一个int类型的值

例4:int (*(*func)[5])(int *p);

未定义标识符func,看左边,是一个*,说明它是一个指针;

跳出这个圆括号,看右边,是一对方括号,说明(*func)是一个数组,一个指向数组的指针;

看左边,是一个*,数组的元素是指针;

跳出这个括号,看右边,是一对圆括号,说明数组中的元素时函数指针,这类函数具有int * 这样的形参;

跳出这个括号,看左边,是一个int,说明这类函数返回的是一个Int类型的值

例5:int (*(*func)(int *p))[5];

未定义标识符func,看左边,是一个*,说明它是一个指针;

跳出这个圆括号,看右边,是一对圆括号,说明func是一个指向函数的指针,这类函数具有int* 这样的参数;

看左边,是一个*,说明这类函数返回的是一个指针;

跳出这个圆括号,看右边,是一对方括号,说明这个返回的指针指向一个具有5个元素的数组;

看左边,是一个int,说明数组的元素是Int类型

[非法] 例6:int func(void)[5]

未定义标识符func,看右边,是一对括号,func是一个函数,没有参数;

由于右边是一对方括号,所以函数返回的是一个具有5个元素的数组;

这个数组的元素是int类型
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: