前言
编程语言的类型模型(type model)一直都是编程语言学习的重点。虽然但是,C语言声明的语法实在是过于奇怪,以至于我们需要花费一些时间认真理解一下,首先思考一下简单的类型模型,考虑下面的C语言声明:
typedef char * string;
string punchline = "I'm a frayed knot";
可以将其分为两部分:变量的类型和变量来理解
被称作 | 是 | |
---|---|---|
变量的类型 | string | char * |
变量 | punchline | “I;m a frayed knot” |
C语言声明的产生
C语言中的声明器(declarator)
简单地说,声明器就是标识符以及和他组合在一起的任何指针、函数符号、数组下标(本表额外添加了初始化内容)
数量 | C语言中的名字 | C语言中出现的形式 |
---|---|---|
零个或多个 | 指针 | const volatile;volatile;; const; * volatile const |
有且只有一个 | 直接声明器 | 标识符;标识符[下标];标识符(参数);(声明器) |
零个或一个 | 初始化内容 | = 初始值 |
声明器是一个很模糊的概念,一个简单的思考方式是C语言的声明器是声明中缺少类型以及对类型限定后剩下的部分,这也可以理解 int *p,*q,r 都是什么类型了(p,q是指针,r是int型变量)
C语言的声明
声明增加了至少一个类型说明符(包括类型说明,存储说明和类型限定符),声明器(一个或多个,逗号分割)分号(语句结束)但也请注意,合法的声明存在限定条件,举例说明:
你也许很快想到,针对这些问题可以用指针解决,所以
- 函数的返回值允许是一个函数指针,如 int(* fun()) ()
- 函数的返回值允许是一个指向数组的指针, 如 int(*foo())[]
- 数组里面允许有函数指针 如 int (*foo[])()
- 数组里面允许有其他数组,所以你经常看到 int foo[][]
优先级规则
C语言声明的优先级规则是阅读C语言声明关键的一步:因为C语言的声明并不是简单的从左到右,下面给出这条规则
A 声明从它的名字开始读取,然后按照优先级顺序依次读取;
B 优先级从高到低依次是:
B.1 声明中被括号括起来的那部分;
B.2 后缀操作符:括号()表示这是一个函数,而方括号[]表示这是一个数组;
B.3 前缀操作符:星号*标识“指向…的指针”;
C 如果const和(或者)volatile关键字的后面紧跟类型说明符(如int,long等),那么它作用于类型说明符,在其他情况下,const和(或)volatile关键字作用于它左边紧邻的指针星号。
分析一个例子:
char * const * (*next) ();
A 首先,确定变量名next
B.1 将括号看成整体,得出next是一个指向..的指针
B.2 考虑括号外面,后缀 () 得出next是一个函数指针,指向一个返回…的函数
B.3 然后,处理前缀 * ,得出函数返回的是另一个指针
C 将 char * const 解释为指向字符的常量指针
得出结论:next是一个指针,它指向一个函数,函数返回另一个指针,返回的指针是一个类型为char的常量指针
对于const,一个方便的理解方法是const默认修饰左边的,否则作用于右边,因此我们可以看到__char * const__是一个char类型的常量指针.给出几个const的例子
语法 | 含义 |
---|---|
const T* | 指向const对象的指针 |
T const * | 指向const对象的指针 |
T * const | 指向对象的cosnt指针 |
const T* const | 指向const对象的const指针 |
T const * const | 指向const对象的const指针 |