C语言中声明一个名称就是把一个标识符与某个C语言对象相关联,如变量、函数或类型,C语言中可以声明的名称包括:变量、函数、类型、类型标志、结构成员与联合成员、枚举常量、语句标号和预处理器宏。除了语句标号和预处理器宏之外,所有标识符都在C语言声明中声明,变量、函数、类型放在声明的声明符中,类型标志、结构成员与联合成员和枚举常量在声明的某种类型说明符中声明,语句标号在C语言函数中出现时声明,而预处理器宏用#define预处理器命令声明。
如下列声明:
extern const volatile unsigned long int i;
习惯上先写存储类说明符extern,然后是类型限定符constvolatile,最后是类型说明符unsignedlong
int。
存储类说明符确定所声明对象的生存期(除了typedef是个特例),声明中最多可以出现一个存储类说明符,具体列举如下:
auto:只在块内的变量声明中允许,表示变量具有本地(自动)生存期(这是默认,因此C语言程序中很少看到auto说明符)。块声明中,若为非函数类型,默认存储类说明符为auto。
extern:出现在顶层或块中的外部函数与变量声明中,表示声明的对象具有静态生存期,连接程序知道其名称。顶层声明中默认存储类说明符为extern,但省略存储类说明符不同于提供extern。块声明中,若是函数,默认存储类说明符为extern。
register:可以用于本地变量或参数声明,作用相当于auto,只不过它要向编译器提供提示说该对象会被频繁使用,应该采取一种最小化访问时间的分配方式。函数参数默认无存储类说明符,如非register,如果有实际需求,可给函数参数添加存储类说明符register。
static:可以放在函数与变量声明中。在函数定义时,其只用于指定函数名而不将函数导出到连接程序。在函数声明中,其表示文件后面会定义声明的函数,存储类为static。在数据声明中,总是表示定义的声明不导出到连接程序。用这个存储类说明符的变量具有静态生存期(而auto则指定本地生存期)。
typedef:表示声明定义新的数据类型名,而不是函数与变量声明。数据类型名出现在变量声明中出现变量名的地方,数据类型本身是变量名要指定的类型。
函数声明符是C99中增加的,函数说明符inline只能在函数声明中出现,这种函数称为内联函数,函数说明符可以多次出现而不改变含义,使用inline提示C实现,函数调用应尽量快。
类型说明符对所声明的程序标识符的数据类型提供一定信息,其它类型信息由声明符指定,类型说明符还可以定义(作为副作用)类型标志、结构成员名与联合成员名和枚举常量。最初,C语言允许省略变量声明和函数定义中的类型说明符,这时默认类型说明符为int,但现代C语言认为这是不良编程风格,事实上C99把它当作错误处理,较早的编译器没有实现void类型,因此函数定义中省略类型说明符的目的是告诉读者这个函数不返回数值(但编译器要假设其返回数值),现代C语言则用void类型声明无返回值的函数。结构、联合或枚举定义的类型指定符定义新类型或枚举常量,如果只要定义类型,则可以从声明中省略所有声明符,只编写类型说明符,无意义的声明通常被忽略。
类型限定符const、volatile与restrict指定类型的其它属性,这些属性只在通过左值访问该类型对象时与类型有关。const与volatile是C89中增加的,restrict是C99中增加的。
const:const限定类型的左值表达式不能用来修改对象,即这种左值不能作为赋值表达式的左操作数或递增与递减运算符的操作数,目的是用const限定符指定数值不变的对象,让C语言编译器保证编程人员不改变这个值。const用于指针声明时,位置不同,效果不同,如下例子:
int * const const_pointer; // 常量指针 const int * pointer_to_const; // 常量数据的指针
volatile:volatile类型限定符告诉标准C语言实现,某些对象可以用实现不能控制的方式改变数值,即易失对象。volatile最常见的用法是对特殊内存地址提供可靠的访问,计算机硬件或中断处理器之类的异步进程使用这些特殊内存地址。
restrict:restrict只能用于限定对象指针或不完整类型,作为C语言编译器的非别名提示,即目前只有指针是访问其所指对象的唯一方式,破坏这个假设会造成不确定行为。这样做的好处是,能帮助编译器进行更好的代码优化,生成更有效率的汇编代码。