c - static 和 extern 一个

c - static and extern one again

我正在检查具有不同链接的声明中可能发生的各种情况,我有 2 个问题。

我。我有以下代码:

#include <stdio.h>  

static int a = 19;
         
   int main(void)
   {
      extern int a;
      {
          extern int a;
          printf("braces - %d\n", a);
      }   
      printf("main - %d\n", a);
  }

clanggcc 编译得很好,19 在两个 pritf 中打印的结果相同。据我所知,根据标准的 6.2.2., 4),所有 a 都是 static。我唯一不明白的是为什么文件范围 a 对于 a 在 main 和大括号中可见?根据脚注 31,文件范围的文件不应该被隐藏吗?当我在其他文件中用不同的值定义另一个 a 时,两个 printfs` 输出仍然是 19.

二.现在我执行以下操作:

#include <stdio.h>  

static int a = 19;
         
   int main(void)
   {
      int a;                           //change in this line
      {
          extern int a;
          printf("braces - %d\n", a);
      }   
      printf("main - %d\n", a);
  }

gcc 大喊 variable previously declared ‘static’ redeclared ‘extern’,而 clang 正常运行并在 main 中为 a 打印 a = 0(是的,它是垃圾值)仍然是 19 岁,戴着牙套。
我猜 gcc 适用于此处 6.2.2。 7) 的标准,而 clang 没有。谁的解释是正确的,这是怎么回事?

我只能假设 gcc ''matches'' a 在 main 中带有 a 的大括号中(没有链接)并使其成为外部链接,并且然后发现它与文件范围 static a 冲突。而且,再一次,为什么不使大括号 a 引用另一个文件中的 a(脚注 31?)?


事实上,我目前的理解接近 here 中接受的答案中的理解,尽管我确实理解 C++ 与 C 存在差异(我问的是 C)。

The only thing that I don't understand in it is that why file-scope a is visible for a in main and braces?

在文件作用域中声明的变量a在main

的块作用域中是可见的
   static int a = 19;
         
   int main(void)
   {
      extern int a;
      //...

直到 main 中的声明重新声明文件范围内的变量。因此 main 中的变量表示在文件范围内声明的相同变量。

在复合语句的块范围内

int main(void)
{
   extern int a;
   {
       extern int a;
       //...

在复合语句的块范围内声明变量a之前,main封闭范围内变量a的声明是可见的。因此,在复合语句中声明的变量表示在函数 main 的封闭块范围内声明的同一个变量。所有三个变量都表示具有内部链接的相同变量。

至于第二个程序则按照C标准(6.2.2标识符的链接)

7 If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined

程序有未定义的行为,因为在函数 main

的块范围内声明的变量
static int a = 19;
     
int main(void)
{
    int a; 
    // ...

隐藏在具有内部链接的文件范围内声明的变量。所以根据C标准(6.2.2 Linkages of identifiers)

4 For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31) if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

在复合语句的块范围内声明的变量a具有外部链接。因此,翻译单元中的相同标识符具有外部和内部链接。