为什么以下代码无法编译?
...
extern int i;
static int i;
...
但如果您颠倒顺序,它会编译成功。
...
static int i;
extern int i;
...
这里发生了什么事?
为什么以下代码无法编译?
...
extern int i;
static int i;
...
但如果您颠倒顺序,它会编译成功。
...
static int i;
extern int i;
...
这里发生了什么事?
这在C++标准中是一个特定的例子,当它讨论声明外部或内部链接的复杂性时给出。它在第7.1.1.7节中,引用如下:
static int b ; // b has internal linkage
extern int b ; // b still has internal linkage
extern int d ; // d has external linkage
static int d ; // error: inconsistent linkage
第3.5.6节讨论了在这种情况下extern
应该如何行为。
发生的情况是这样的:static int i
(在此示例中)是定义,其中static
表示i
具有内部链接。当static
后面出现extern
时,编译器看到符号已经存在,并接受它已经具有内部链接并继续执行。这就是为什么您的第二个示例可以编译的原因。
另一方面,extern
是一个声明,它隐含地说明符号具有外部链接,但实际上不创建任何内容。由于您的第一个示例中没有i
,编译器将i
注册为具有外部链接,但当它到达static
时,它发现不兼容的语句表明它具有内部链接,并给出错误。
换句话说,这是因为声明比定义“软”。例如,您可以多次声明相同的内容而不出错,但只能定义一次。
我不知道在C中是否相同(但netcoder在下面的答案告诉我们,C标准包含相同的要求)。
C++:
7) 在命名空间作用域中声明的名称,如果没有存储类说明符,则具有外部链接性,除非它因先前的声明而具有内部链接性,并且只要它没有被声明为 const。声明为 const 且未显式声明为 extern 的对象具有内部链接性。
因此,第一个尝试首先给 i
外部链接性,然后再给它内部链接性。
第二个则首先给它内部链接性,第二行不尝试给它外部链接性,因为它之前已经被声明为内部链接性。
8) 对于给定实体的连续声明所暗示的链接必须一致。也就是说,在给定作用域内,每个声明相同变量名或函数名的重载都应该暗示相同的链接。但是,在给定一组重载函数中,每个函数可以具有不同的链接。
[ 示例:
[...]
static int b; // b has internal linkage
extern int b; // b still has internal linkage
[...]
extern int d; // d has external linkage
static int d; // error: inconsistent linkage
[...]
extern int i
表示整数i
在某个其他模块(对象文件或库)中被定义。这是一个声明。编译器不会在此对象中分配存储空间,但它将在程序的其他地方使用变量时识别该变量。
int i
告诉编译器为i
分配存储空间。这是一个定义。如果其他C++(或C)文件有int i
,链接器将抱怨int i被定义了两次。
static int i
与上述类似,具有额外的功能,即i
是本地的。即使它们声明extern int i
,也无法从其他模块访问它。人们在这种情况下使用关键字static来保持i的本地化。