C 为什么';外部';存储类在函数中的工作方式不同?

C 为什么';外部';存储类在函数中的工作方式不同?,c,extern,storage-class-specifier,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

下面的代码段工作正常

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

在第二种情况下,在一个范围内有两个
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;
}
#包括
int i=21;
内部主(空)
{
外部国际一级;
i=37;
{
int i=57;
printf(“%d\n”,i);
}
printf(“%d\n”,i);
返回0;
}
这编译正常(除非在使用GCC或Clang时在编译选项中包含
-Wshadow
),并在输出上生成
57
37
(如a中所指出)


另请参见

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

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

具有文件作用域的对象的标识符声明 没有初始值设定项,也没有存储类说明符或 存储类说明符static构成了一个 定义。如果翻译单元包含一个或多个暂定 标识符的定义,并且翻译单元不包含 该标识符的外部定义,则该行为 就好像翻译单元包含一个文件范围声明一样 标识符,具有转换结束时的复合类型 单位,初始值设定项等于0

您在第一个代码片段中看到的只是对
i
的初步定义。一个对象可以有任意多个暂定定义(但只允许有一个定义):

这是有效的

这里,
i
具有外部链接,并已初步定义。如果
i
是在同一翻译单元的某个地方定义的,那么这就是
i
的实际定义。如果在翻译单元中找不到
i
的其他定义,则这将成为完整定义,如同定义如下:

int i = 0;

int main(void) {
   return 0;
}

但是第二个片段
inti不是一个暂定定义。只能暂时定义具有外部链接的对象。在第二个代码片段中,声明
extern int i表示
i
是通过外部链接在其他地方定义的。但是下一行
inti表示
i
定义时没有链接(本地自动变量没有任何链接——这不是一个暂定定义)。因此,
i
的定义存在冲突。因此,第一个片段可以,但第二个片段不行。

应该补充说,当我第一次遇到“暂定定义”这个词时,该示例将打印
57
然后
37
。我在C++中工作,我认为席上不存在这样的东西。是的,C++没有临时定义。
int i = 0;

int main(void) {
   return 0;
}