一般地,声明具有下列形式:
声明说明符 声明符;
声明说明符(declaration specifier)描述声明的变量或函数的性质。
声明符(declarator)给出了它们的名字,并且可以提供关于其性质的额外信息。
声明说明符分为以下 4 大类:
在声明中最多可以出现一种存储类型;如果存储类型存在,则必须把它放置在最前面。
声明可以包含零个或多个类型限定符。
类型限定符和类型说明符必须跟随在存储类型后边,但是两者的顺序没有限制。
C程序中的每个变量都具有以下 3 个性质。
变量的默认存储期限、作用域和链接都依赖于变量声明的位置:
int i; //具有静态存储期限、文件作用域和外部链接
void fun(void)
{
int j; //具有自动存储期限、块作用域,并且无链接
}
可以通过指定明确的存储类型(auto、static、extern 和 register)来改变变量的性质。
auto 存储类型只对属于块(用花括号括起来的多个语句)的变量有效。
auto 变量具有自动存储期限、块作用域,并且无链接。
auto 存储类型几乎从来不用明确地指明,因为对于在块内部声明的变量,它是默认的。
static 存储类型可以用于全部变量,而无需考虑变量声明的位置。
但是,作用于块外部声明的变量和块内部声明的变量时会有不同的效果:
int i; //具有静态存储期限、文件作用域和内部链接
void fun(void)
{
int j; //具有静态存储期限、块作用域和无链接
}
static 变量 和 auto 变量的比较:
extern 存储类型使几个源文件可以共享同一个变量。
变量的 extern 声明不是定义,它只是提示编译器需要访问定义在别处的变量。
file1.c
int a = 3,b = 4;//在file1.c中定义(初始化)
file2.c
extern int a,b; //在file2.c中声明
int main()
{
printf("%d,%d\n",a,b);
}
extern 声明的变量始终具有静态存储期限,其作用域依赖于声明的位置。
在大多数情况下,变量会定义在另一个文件中,并且具有外部链接。
声明变量具有 register 存储类型就要求编译器把变量存储在寄存器中,而不是像其他变量一样保留在内存中。
和变量声明一样,函数声明的(和定义)也可以包括存储类型,但是选项只有 extern 和 static。
在函数声明开始处的单词 extern 说明函数具有外部链接,也就是允许其他文件调用此函数。
如果不指明函数的存储类型,那么会假设函数具有外部链接。
在函数声明开始处的单词 static 说明函数具有内部链接,也就是说只能在定义函数的文件内部调用此函数。
任何变量的声明都可以使用 const 限定符限定,该限定符指定变量的值不能被修改。
const 对象必须声明的同时初始化。
const int buffsize = 255;
初始值可以是任意复杂表达式:
int i = 42;
const int ci = i;
const int j = get_size();
默认状态下,const 对象仅在文件内有效。
如果想在多个文件之间共享 const 对象,在变量的定义和声明之前都添加 extern 关键字。
文件1:
extern const int buffsize = fcn(); //该常量能被其他文件访问
文件2:
extern const int buffsize; //使用其它文件的常量
要想存放常量的地址,只能使用指向常量的指针(pinter to const)。
指向常量的指针不能用于改变其所指对象的值。
const double pi = 3.14;
const double* ptr = π
允许指向常量的指针指向一个非常量的对象:
double pi = 3.14;
const double* cptr = π //不能通过*cptr改变pi的值
允许把指针本身定位常量。
常量指针(const pointer)必须初始化,而且一旦初始化完成,它的值就不能再改变了。
把 * 放在 const 关键字之前用以说明指针是一个常量。
int errNumb = 0;
int* const curErr = &errNumb; //cuErr将一直指向errNumb
指向常量的常量指针
const double pi = 3.14159;
const double* const pip = π //指向常量对象的常量指针。
在C99中,关键字 restrict 可以出现在指针的声明中:
int* restrict p;
用 restrict 声明的指针叫做受限指针(restricted pointer)。
这样做的目的是,如果指针 p 指向的对象在之后需要修改,那么该对象不会允许通过除指针 p 之外的任何方式访问。
其他访问对象的方式包括让另一个指针指向同一个对象,或者让指针 p 指向命名变量。
具有静态存储期限的变量的初始化必须是常量。
具有静态存储期限的变量默认情况的值为零。
具有动态存储期限的变量的初始化必须可以是变量也可以是常量。
具有动态存储期限的变量没有默认的初始值。
包含在花括号中的数组、结构或联合的初始化必须只包含常量表达式。
自动类型的结构或联合的初始化可以是另外一个结构或联合。