2

以下代码段工作正常

extern int i;
int i;

int main(){
    return 0;
}

我在这里得到的是,'i'被声明然后定义。因为只有一个定义,所以这很好。

int main(){
    extern int i;
    int i;
    return 0;
}

现在,上面给出了以下错误

new.cpp: In function ‘int main()’:
new.cpp:5:6: error: redeclaration of ‘int i’
  int i;
      ^
new.cpp:4:13: note: previous declaration ‘int i’
  extern int i;

这里有什么问题?这里也有“i”的单一定义。

4

2 回答 2

3

要了解其中的区别,您需要熟悉 C 中称为“暂定定义”的概念。引用 C 标准:

C11,草案,§6.9.2,外部对象定义

具有文件范围的对象的标识符声明没有初始化程序,并且没有存储类说明符或具有存储类说明符 static,构成暂定定义。如果翻译单元包含一个或多个标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,则行为与翻译单元包含该标识符的文件范围声明完全相同,复合类型为翻译单元的末尾,初始化器等于 0。

您在第一个片段中的内容只是i. 您可以根据需要对对象进行任意数量的暂定定义(但只允许一个定义):

int i; // tentative definition
int i; // tentative definition
int i; // tentative definition

int main(void) {
   return 0;
}

已验证。

在这里,i有外部联系并暂定。如果i在同一个翻译单元的某个地方定义,那么这将是i. 如果i在翻译单元中没有找到 is 的其他定义,则这将成为完整定义,就好像它的定义如下:

int i = 0;

int main(void) {
   return 0;
}

但是第二个片段int i;不是一个暂定的定义。只能暂时定义具有外部链接的对象。在第二个片段中,声明说在其他地方定义了外部链接。但是下一行说是没有链接定义的(局部自动变量没有任何链接——这不是一个暂定的定义)。所以 . 的定义存在冲突。因此,第一个片段很好,但第二个片段不是。extern int i;iint i;ii

于 2015-09-12T06:57:02.937 回答
0

i在第二种情况下,一个范围内有两个声明。有人说“i在这个函数之外定义了一个变量”;另一个说“i这个函数内部定义了一个变量”。如果没有新的范围,这是不允许的。

规则是不同的内部和外部功能。

请注意,您可以使用:

#include <stdio.h>

int i = 21;

int main(void)
{
    extern int i;
    i = 37;
    {
    int i = 57;
    printf("%d\n", i);
    }
    printf("%d\n", i);
    return 0;
}

这可以编译(除非您-Wshadow在使用 GCC 或 Clang 时包含在编译选项中),并在输出中生成57和(正如CoffeeAndCode评论37中指出的那样)。

另请参阅如何extern在源文件之间共享变量?

于 2015-09-12T06:28:28.430 回答