关键字static和extern的含义取决于上下文。C语言有6个关键字作为存储类别说明符:auto、register、static、extern、_Thread_local和typedef。typedef关键字与任何内存存储无关,把它归于此类有一些语法上的原因。尤其是,在绝大多数情况下,不能在声明中使用多个存储类别说明符,所以这意味着不能使用多个存储类别说明符作为typedef的一部分。唯一例外的是_Thread_local,它可以和static或extern一起使用。
auto说明符变量是自动存储期,只能用于块作用域的变量声明中。由于在块中声明的变量本身就具有自动存储期,所以使用auto主要是为了明确表达要使用与外部变量同名的局部变量的意图。
register说明符也只用于块作用域的变量,它把变量归为寄存器类别,请求最快速度访问该变量。同时,还保护了该变量的地址不被获取。
用static说明符创建的对象具有静态存储期,载入程序时创建对象,当程序结束时对象消失。如果static用于文件作用域声明,作用域受限于该文件。如果static用于块作用域声明,作用域受限于该块。因此,只要程序在运行对象就存在并保留其值,但是只有在执行块内的代码时,才能通过标识符访问。块作用域的静态变量无链接。文件作用域的静态变量具有内部链接。
extern说明符表明声明的变量定义在别处。如果包含extern的声明具有文件作用域,则引用的变量必须具有外部链接。如果包含extern的声明具有块作用域,则引用的变量可能具有外部链接或内部链接,这链接取决于该变量的定义声明。
小结:存储类别
自动变量具有块作用域、无链接、自动存储期。它们是局部变量,属于其定义所在块(通常指函数)私有。寄存器变量的属性和自动变量相同,但是编译器会使用更快的内存或寄存器储存它们。不能获取寄存器变量的地址。
具有静态存储期的变量可以具有外部链接、内部链接或无链接。在同一个文件所有函数的外部声明的变量是外部变量,具有文件作用域、外部链接和静态存储期。如果在这种声明前面加上关键字static,那么其声明的变量具有文件作用域、内部链接和静态存储期。如果在函数中用static声明一个变量,则该变量具有块作用域、无链接、静态存储期。
具有自动存储期的变量,程序在进入该变量的声明所在块时才为其分配内存,在退出该块时释放之前分配的内存。如果未初始化,自动变量中是垃圾值。程序在编译时为具有静态存储期的变量分配内存,并在程序的运行过程中一直保留这块内存。如果未初始化,这样的变量会被设置为0。
具有块作用域的变量是局部的,属于包含该声明的块私有。具有文件作用域的变量对文件(或翻译单元)中位于其声明后面的所有函数可见。具有外部链接的文件作用域变量,可用于该程序的其他翻译单元。具有内部链接的文件作用域变量,只能用于其声明所在的文件内。
示例
partb.c文件
#include <stdio.h>
// 引用式声明,外部链接
extern int count;
// 静态定义,内部链接
static int total = 0;
// 函数原型
void accumulate(int k); //在此文件中为可选 (即可省略原型声明)
void accumulate(int k) // k具有块作用域,无链接
{
// 静态,无链接
static int subtotal = 0;
if (k <= 0)
{
printf("loop cycle: %d\n", count);
printf("subtotal: %d; total: %d\n", subtotal, total);
}
else
{
subtotal += k;
total += k;
}
}
Main.c文件
//Visual Studio中加上这句才可以使用scanf()
//否则只能使用scanf_s()
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//malloc()、free()
#include <stdlib.h>
#include <time.h>
void report_count();
void accumulate(int k);
int count = 0; // 文件作用域,外部链接
//argc: 参数个数 argv[]: 参数数组
//int main(int argc, char **argv)
int main(int argc, char *argv[])
{
int value; // 自动变量
register int i; // 寄存器变量
printf("Enter a positive integer (0 to quit): ");
while (scanf("%d", &value) == 1 && value > 0)
{
++count; //使用文件作用域变量
for (i = value; i >= 0; i--)
accumulate(i);
printf("Enter a positive integer (0 to quit): ");
}
report_count();
system("pause");
return 0;
}
void report_count()
{
printf("Loop executed %d times\n", count);
}
运行测试