为什么'extern'存储类在函数中的工作方式不同?

时间:2015-09-12 06:12:35

标签: c extern storage-class-specifier

以下代码段正常

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'的单一定义。

2 个答案:

答案 0 :(得分:3)

要理解其中的差异,您需要熟悉C中名为暂定定义的概念。引用C标准:

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

  

具有文件范围的对象的标识符声明   没有初始化程序,没有存储类说明符或没有   存储类说明符静态,构成一个暂定的   定义。如果翻译单元包含一个或多个暂定单元   标识符的定义,翻译单元包含否   该标识符的外部定义,然后行为是完全正确的   好像翻译单元包含一个文件范围声明   标识符,在翻译结束时使用复合类型   单位,初始化程序等于0。

第一个代码段中的内容仅是i的暂定定义。您可以根据需要为对象设置尽可能多的暂定定义(但只允许一个定义):

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

int main(void) {
   return 0;
}

有效。

在这里,i具有外部联系并暂时定义。如果i在同一翻译单元的某个位置定义,那么这将是i的实际定义。如果在翻译单元中找不到i的其他定义,那么这将成为完整定义,就像定义如下:

int i = 0;

int main(void) {
   return 0;
}

但第二个代码段int i; 不是一个暂定的定义。只能暂时定义具有外部链接的对象。在第二个片段中,声明extern int i;表示i在其他位置使用外部链接定义。但下一行int i;表示i定义没有链接(本地自动变量没有任何链接 - 这是暂定定义)。因此i的定义存在冲突。因此,第一个片段很好,但第二个不是。

答案 1 :(得分: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;
}

编译好(除非在使用GCC或Clang时在编译选项中包含-Wshadow),并在输出上生成5737(由{{3指出)在CoffeeAndCode)。

另见comment