最近在写c语言的时候感觉好像C语言的声明好像就这么几个师太简单了?还是我理解的太浅了,然后去看了看书查了查资料,然后进行了相关的整理,将部分的资料贴了出来。
我们常见的对声明的描述是这样的:
存储类别 类型限定词 类型 标识符
这里看上去是没啥问题,但是有没有感觉好像所有的声明好像都是这样的,静止的,死板的,以它为基础往上一套就可以了。
但是不然其实C语言的声明的组织形式是以嵌套为基础的,是用嵌套声明组织起来的。
C89对声明的形式是如何规定的:
声明:
声明说明符 初始化声明符表opt [opt的意思是option,可选]
声明说明符:
存储类说明符 声明说明符opt
类型说明符 声明说明符opt
类型限定符 声明说明符opt
一个声明说明符可以包含另一个声明说明符,这就是声明的嵌套,这种嵌套贯穿于整个声明之中,今天我们看来一个非常简单的声明,其实就是由多个声明嵌套组成的,例如
static const int i=10, j=20, k=30;
变量i前面就是声明说明符部分,有三个声明说明符:static const int,static是一个存储类说明符,它属于这种形式:
1、static 声明说明符, static后面的声明说明符就是const int,const是一个类型限定符,这也是个嵌套,它是由,const 声明说明符组成,最后的int是一个类型说明符,到这里已经没有嵌套了,int就是最底的一层。对于存储类说明符、类型说明符和类型限定符的排列顺序,C标准并没有规定其顺序,谁嵌套谁都可以。换言之,上面的声明可以写成:
int static const i=10, j=20, k=30;或者const int static i=10, j=20, k=30;
这无所谓,跟原声明是一样的。再举一个有趣的例子:
const int *p;与int const *p;
有些人会对后面一种形式感到困惑,因为他一直以来学习的都是那种死板的形式,因此他无法理解为什么那个const可以放在int的后面。实际上对于标准来说,这是再正常不过的行为了。
上面举的例子是变量的声明,函数的声明也同样道理,例如:
static const int func(void);
......
int main(void)
{
int static const (*p)(void);
p=func;
.........
return 0;
}
const int static func(void)
{
.......
return 0;
}
然后对上面的整理一下:
声明static const int i=10, j=20, k=30;的int后面的部分就是初始化声明符表,这比较容易理解,这个符表实际上也是嵌套的:
初始化声明符表:
初始化声明符
初始化声明符表, 初始化声明符
初始化声明符:
声明符
声明符=初值
声明符是初始化声明符的主体,现在来讨论一下声明符是如何规定的:
声明符:
指针opt 直接声明符
这里写的指针opt指的是那个指针声明符*,要注意的是,*属于声明符,而不是声明说明符的一部分。
指针opt又包含:
指针:
* 类型限定符表opt
* 类型限定符表opt 指针
其实在前面的时候有一个常见的问题,就是const int *p;与int * const p的区别,第一个声明的const属于声明说明符,它跟int一起,是用来说明*p这个声明符的,因此const修饰的是p所指向的那个对象,这个对象是const的。而第二个声明的const是声明符的一部分,它修饰的对象是p本身,因此p是const的。大白话就是:一个是地址不可变,一个是变量不可变。
直接声明
直接声明符:
标识符
(声明符)
直接声明符[常量表达式opt]
直接声明符(形式参数类型表)
直接声明符(标识符表opt)
类型限定符表:
类型限定符
类型限定符表 类型限定符
typedef int a[10];
typedef void (*p)(void);
上面的语句把a声明为具有10个int元素的数组的类型别名,p是一种函数指针的类型别名。虽然在功能上,typedef可以看作一个跟int PARA分离的动作,但语法上typedef属于存储类声明说明符,因此严格来说,typedef int PARA整个是一个完整的声明。