C中的extern关键字应用于C变量(数据对象)和C函数。基本上,extern关键字扩展了C变量和C函数的可见性。这可能就是它诶命名为extern的原因。
虽然大多数人可能理解变量或函数的“声明(declaration)” 和 “定义(definition)” 之间的区别,但为了完整性,先澄清协议爱
- 变量或函数的声明只是简单地声明变量或函数存在于程序中的某个位置,但没有为他们分配内存。变量或函数的声明起着重要作用——它“告诉”程序它的类型。在函数的声明中,它还“告诉”程序参数、数据类型、这些参数的顺序以及函数的返回类型。这就是声明的全部内容。
- 说到定义,当我们定义一个变量或函数时,除了要做声明所做的一切之外,它还为该变量或函数分配内存。
- extern是external的简称
- 当某个特定文件需要访问另一个文件中的变量时,会使用extern变量。
C 中extern语法
在C中定义外部变量的语法只是在变量声明之前使用extern关键字。
extern data_type variable_name;
C中extern变量的例子
#include <stdio.h> extern int a; // int var; -> declaration and definition // extern int var; -> declaration
int main()
{ printf("%d", a); return 0;
}
C中extern变量的属性
- 当我们写
extern some_data_type some_variable_name;
时,没有分配内存。只声明了变量的属性。 - 文件中允许有多个外部变量声明。但自动变量的情况并非如此。
- extern变量对编译器说:“在我的范围之外,你可以找到我声明的变量的定义”
- 编译器相信外部变量所说的一切都是真的,不会产生错误。当链接器发现不存在这样的变量的定义时,它会抛出错误。
- 当一个外部变量被初始化时,就会为其分配内存,并将其视为已定义。
变量或函数可以声明任意次,但只能定义一次。(记住一个基本原则,即同一个变量或函数不能有两个位置。)
现在回到extern关键字。
首先,考虑函数中extern的使用。事实证明,当一个函数被声明或定义时,extern关键字是隐式假定的。当我们写
int foo(int arg1, char arg2);
编译器将其视为
extern int foo(int arg1, char arg2);
由于 extern 关键字将函数的可见性扩展到整个程序,因此可以在整个程序的任何文件中的任何位置使用(调用)函数,前提是这些文件包含函数的声明。(有了函数的声明,编译器就知道函数的定义存在于其他地方,然后继续编译文件)。这都是关于extern和函数的。
现在考虑变量中extern的使用。首先,如果在不定义变量的情况下声明变量?你可以这样做:
extern int var;
这里,声明了一个名为 var 的整数类型的变量(它还没被定义,所以目前为止还没有为 var 分配内存)。我们可以随心所欲地多次进行这样的声明。现在,如何定义 var?你可以这样做:
int var = 10;
在这一行中,声明并定义了一个名为 var 的整型变量(请记住,定义是声明的超集)。因为这是一个定义,因此还为 var 分配了内存。现在惊喜来了,当我们声明/定义一个函数时,我们看到 extern 关键字是隐式存在的。但变量的情况并非如此。如果是这样的话,就永远不会为它们分配内存。因此,当我们想要在不定义变量的情况下声明变量时,需要显式地包含 extern 关键字。此外,由于 extern 关键字将可见性扩展到这个程序,通过将 extern 关键字与变量一起使用,可以在程序中的任何地方使用该变量,只要包含其声明,变量的定义是在其他地方。
用一个例子来尝试理解 extern .
例1
int var;
int main(void)
{ var = 10; return 0;
}
程序编译成功。var是全局定义(并隐式声明)的。
例2
extern int var;
int main(void)
{ return 0;
}
程序编译成功。这里 var 仅仅声明了。注意 var 从未使用过,因此不会出现任何问题。
例3
extern int var;
int main(void)
{ var = 10; return 0;
}
程序在编译中抛出一个错误(在链接阶段),因为 var 声明了,但是没有在任何地方定义。本质上,var 没有分配任何内存。该程序试图将一个根本不存在的变量的值更改为10。
例4
// As we are importing the file and henceforth the
// defination
#include "somefile.h" // Declaring the same variable
extern int var; // int var; // It will throw compiler error as compiler will get // confused where the variable is defined int main(void)
{ var = 10; return 0;
} // Now it will compile and run successfully
输出
10
注意: 这里出现了另一种情况,如果我们在上面的代码片段中不用extern声明呢?
考虑假设 somefile.h 文件中包含了 var 的定义,该程序将编译成功。当我们在一个文件中声明变量并在另一个文件中定义时,使用 ‘extern’ 关键字修饰变量。但在这里,当我们在声明该变量的文件中导入相同的文件时,将产生编译错误。
这是因为我们仍然必须在声明该变量的文件中使用 extern 关键字,以便告诉编译器该变量是在其他地方定义的,不会分配新的空间,否则它将创建另一个内存块,‘extern’ 关键字就没用了。
例5
extern int var = 0;
int main(void)
{ var = 10; return 0;
}
你认为这个程序会正常运行吗?好吧,这是来自C标准的另一个惊喜。如果一个变量只是被声明了,且在声明时也被初始化了,那么会为这个变量分配内存——换言之,这个变量认为是已经定义的。因此,按照C标准,这个程序成功编译并执行。
这是对 C 中 extern 关键字的初步研究。
简而言之,我们可以说:
- 可以执行声明任意次,但只能定义一次。
- extern 关键字用于扩展变量/函数的可见性。
- 由于默认情况下函数在整个程序中是可见的,因此在函数声明或定义中不需要使用 extern。它的使用是隐含的。
- 当 extern 与变量一起使用时,它只是声明,而不是定义。
- 例外情况,当一个变量在声明时被初始化,它被视为变量的定义。