外部级别声明的存储类说明符

外部变量是文件范围内的变量。 它们在任何函数的外部定义,并且可能对许多函数可用。 只能在外部级别定义函数,因此不能将其嵌套。 默认情况下,所有对同名外部变量和函数的引用都是对同一个对象的引用,也就是说它们具有外部链接。 (可以使用 static 关键字来替代此行为。)

外部级别的变量声明要么是变量的定义(定义声明),要么是对其他地方定义的变量的引用(引用声明)。

(隐式或显式)初始化变量的外部变量声明是变量的定义声明。 外部级别的定义可采用多种形式:

  • 使用 static 存储类说明符声明的变量。 可以使用常数表达式来显式初始化 static 变量,如初始化中所述。 如果省略初始值设定项,默认情况下变量将初始化为 0。 例如,这两个语句都被视为变量 k 的定义。

    static int k = 16;
    static int k;
    
  • 在外部级别显式初始化的变量。 例如,int j = 3; 是变量 j 的定义。

在外部级别(即在所有函数之外)的变量声明中,可以使用 staticextern 存储类说明符,也可以完全省略存储类说明符。 不能在外部级别使用 autoregisterstorage-class-specifier 终止符。

一旦在外部级别定义变量,该变量在翻译单元的其余部分便可见。 该变量在同一源文件中的声明之前不可见。 此外,除非引用声明使其可见,否则它在程序的其他源文件中不可见,如下文所述。

static 相关的规则包括:

  • 在所有块之外声明的、没有 static 关键字的变量在整个程序中始终保持自己的值不变。 若要限制它们对特定翻译单元的访问,必须使用 static 关键字。 这给了它们内部链接。 若要使其成为整个程序的全局变量,请忽略显式存储类或使用关键字 extern(请参阅下一个列表中的规则)。 这给了它们外部链接。 内部链接和外部链接也在链接中进行了讨论。

  • 在程序中,只可在外部级别定义变量一次。 可以在不同的翻译单元中定义另一个具有相同名称和 static 存储类说明符的变量。 由于每个 static 定义只在它自己的翻译单元中可见,因此不会发生任何冲突。 这提供了一种实用的方法来隐藏标识符名称,这些标识符名称必须在一个翻译单元的函数之间共用,但对其他翻译单元不可见。

  • static 存储类说明符也可以应用于函数。 如果你声明函数 static,那么它的名称在声明它的文件之外是不可见的。

有关使用 extern 的规则为:

  • extern 存储类说明符声明对在其他位置定义的变量的引用。 可以使用 extern 声明让另一个源文件中的定义可见,或让变量先于同一源文件中的定义可见。 一旦你在外部级别声明了对变量的引用,此变量就在声明的引用所在的整个翻译单元的其余部分都是可见的。

  • 若要使 extern 引用有效,必须定义其引用的变量一次,并且仅在外部级别定义一次。 此定义(没有 extern 存储类)可位于构成程序的任何翻译单元中。

示例

下面的示例阐释了外部声明:

/******************************************************************
                      SOURCE FILE ONE
*******************************************************************/
#include <stdio.h>

extern int i;                // Reference to i, defined below
extern void other ( void );  // Reference to other(), defined in second source file
void next( void );           // Function prototype

int main()
{
    i++;
    printf_s( "%d\n", i );   // i equals 4
    next();
}

int i = 3;                  // Definition of i

void next( void )
{
    i++;
    printf_s( "%d\n", i );  // i equals 5
    other();
}

/******************************************************************
                      SOURCE FILE TWO
*******************************************************************/
#include <stdio.h>

extern int i;              // Reference to i in
                           // first source file
void other( void )
{
    i++;
    printf_s( "%d\n", i ); // i equals 6
}

此示例中的两个源文件包含 i 的总共三个外部声明。 仅一个声明是“定义声明”。该声明

int i = 3;

定义全局变量 i 并使用初始值 3 对其进行初始化。 使用 extern 的第一个源文件顶部的 i 的“引用”声明让全局变量先于文件中的定义声明可见。 此外,第二个源文件中的 i 的引用声明使变量在该源文件中可见。 如果翻译单元中未提供变量的定义实例,则编译器假定有

extern int x;

一个引用声明,并且定义引用

int x = 0;

出现在程序的另一个翻译单元中。

所有三个函数(mainnextother)都执行同一任务:它们增大 i 并将其打印。 打印值 4、5 和 6。

如果变量 i 还没有被初始化,则会自动设置为 0。 在这种情况下,值 1、2 和 3 可能已打印。 有关变量初始化的信息,请参阅初始化

请参阅

C 存储类