/* global.c-- uses an external variable */#include <stdio.h>int units = 0;/* an external variable*/void critic(void);int main(void){extern int units;/* an optional redeclaration */printf("How many pounds to a firkin of butter?n");scanf("%d", &units);while ( units != 56)critic();printf("You must have looked it up!n");return 0;}void critic(void){/* optional redeclaration omitted */printf("No luck, my friend. Try again.n");scanf("%d", &units);}下面是该程序的输出示例:
How many pounds to a firkin of butter?注意 , critic()是如何读取units的第2个值的 。当while循环结束时 , main()也知道units的新值 。所以main()函数和critic()都可以通过标识符units访问相同的变量 。用C的术语来描述是 , units具有文件作用域、外部链接和静态存储期 。
14
No luck, my friend. Try again.
56
You must have looked it up!
(We did.)
把units定义在所有函数定义外面(即外部) , units便是一个外部变量 , 对units定义下面的所有函数均可见 。因此 , critics()可以直接使用units变量 。
类似地 , main()也可直接访问units 。但是 , main()中确实有如下声明:
extern int units;本例中 , 以上声明主要是为了指出该函数要使用这个外部变量 。存储类别说明符extern告诉编译器 , 该函数中任何使用units的地方都引用同一个定义在函数外部的变量 。再次强调 , main()和critic()使用的都是外部定义的units 。外部名称C99和C11标准都要求编译器识别局部标识符的前63个字符和外部标识符的前31个字符 。这修订了以前的标准 , 即编译器识别局部标识符前31个字符和外部标识符前6个字符 。你所用的编译器可能还执行以前的规则 。外部变量名比局部变量名的规则严格 , 是因为外部变量名还要遵循局部环境规则 , 所受的限制更多 。
定义和声明下面进一步介绍定义变量和声明变量的区别 。考虑下面的例子:
int tern = 1;/* tern defined*/main(){external int tern;/* use a tern defined elsewhere */这里 , tern被声明了两次 。第1次声明为变量预留了存储空间 , 该声明构成了变量的定义 。第2次声明只告诉编译器使用之前已创建的tern变量 , 所以这不是定义 。第1次声明被称为定义式声明(defining declaration) , 第2次声明被称为引用式声明(referencing declaration) 。关键字extern表明该声明不是定义 , 因为它指示编译器去别处查询其定义 。假设这样写:
extern int tern;int main(void){编译器会假设tern实际的定义在该程序的别处 , 也许在别的文件中 。该声明并不会引起分配存储空间 。因此 , 不要用关键字extern创建外部定义 , 只用它来引用现有的外部定义 。外部变量只能初始化一次 , 且必须在定义该变量时进行 。假设有下面的代码:
// file one.cchar permis = 'N';...// file two.cextern char permis = 'Y';/* error */file_two中的声明是错误的 , 因为file_one.c中的定义式声明已经创建并初始化了permis 。【c语言外部链接的静态变量的四种类型】
推荐阅读
- 世界上使用最广泛的语言是什么?
- 我的 Linux 故事:用开源打破语言壁垒
- gcc编译器编译过程和链接过程
- C语言头文件路径剖析
- C语言的自定义输入和输出的三种方法
- C语言处理字符串的7个函数
- 编写C程序控制LED
- C语言的指针与多维数组
- C语言的数组的构建与打印
- Fyne - Go语言的跨平台UI工具包
