外部,内部和没有联系或为什么这不起作用?

时间:2016-09-29 10:07:00

标签: c language-lawyer linkage

根据C标准:

  

在构成整个程序的翻译单元和库集中   声明特定标识符   外部链接   表示相同的对象或   功能。在一个翻译单元内,标识符的每个声明都有   内部   联动   表示相同的对象或功能。标识符的每个声明   无   联动   表示一个独特的实体。

在我的例子中,我们有三个单独的声明,每个标识符具有不同的链接。所以为什么这不起作用?

static int a; //a_Internal

int main(void) {
    int a; //a_Local
    {
        extern int a; //a_External
    }
    return 0;
}

错误:

  

在功能'主要':   第9行:错误:先前声明的变量'静态'重新宣布' extern'

为什么编译器坚持要重新声明我而不是尝试访问另一个文件中的外部对象?

有效的C ++示例供参考:

static void f();
static int i = 0;               // #1
void g() {
  extern void f();              // internal linkage
  int i;                        // #2 i has no linkage
  {
    extern void f();            // internal linkage
    extern int i;               // #3 external linkage
  }
}

Clang和VC似乎都适合我的C示例;只有某些版本的GCC(并非所有版本)都会产生上述错误。

3 个答案:

答案 0 :(得分:16)

§6.2.2,7说:

  

如果在翻译单元中,同时出现两个标识符   内部和外部联系,行为未定义。

因此,您的计划有undefined behaviour

§6.2.2,4表示

extern int a; //a_External

具有外部链接,因为范围int a; //a_Local中可见的先前声明具有无链接。但

static int a; //a_Internal

使用内部链接声明a。因此,根据§6.2.2,7,它是 undefined

答案 1 :(得分:2)

编译器发出此错误,因为在a_Internal范围内,仍然可以访问a_Internal,因此您将static中的extern重新声明为a_External a,因为static int a1; //a_Internal int main(void) { int a2; //a_Local { extern int a3; //a_External } return 0; } 的名称冲突。可以使用不同的变量名来解决此问题,例如:

1        17      13       83       0       0           1          2      0      0    104     0   13
2         1       0       18       0       0           0          0      0      0      4     1   13
3         1       1       58       0       0           0          0      0      0      4     1   21
4         4      15      174       9       0          15          0      0      0    154     0   21
5         0       0        8       0       0           0          1      0      0      4     1   20
6         0       1        4       0       0           0          1      0      0      3     1   20
7         0       0      253       0       0           0          1      0      0     21     1   17
8         0       0        0       0       0           0          1      0      0      7     1   17
9         0       1       49       0       0           0          1      0      0      4     1   11
10        4       3       54       1       0           1          3      0      0     21     0   11
11        0       0        0       0       0           0          1      0      0      5     1   11
12        0       0        0       0       0           0          1      0      0      5     1   11
13        0       0        0       0       0           0          1      0      0      7     1   11
14        0       0        0       0       0           0          0      0      0      4     1   11
15        1       0        0       0       0           0          0      0      0      4     1   11
16        0       2        0       0       0           0          0      0      0      4     1   10
17        0       1        5       0       0           0          1      0      0     33     1   10
18        0       0        4       0       0           9          1      0      0     79     1   14
19        0       0        0       0       0           0          3      0      0     33     1   14
20        0       0        2       0       0           0          0      0      0      4     1   14
21        0       1        9       0       0           0          1      0      1     37     1   14
22        0       0        2       0       0           0          2      0      0      8     1   21
23        0       0        7       0       0           0          2      0      0      7     1   21
24        0       0        1       0       0           0          2      0      0      8     1   21
25        0       0      207       0       0           0          2      0      0      7     1   21
26        0       0        0       0       0           0          0      0      0      8     1   15
27        0       0        0       0       0           0          0      0      0      4     1   18
28        0       0        1       0       0           5          0      0      0    135     1   18
29        0       0        0       0       0           0          0      0      0      4     1   18
30        0       0       19       0       0           0          0      0      0      4     1   22
31        0       0       95       0       0           0          0      0      0      4     1   22
32        2       7      130       6       0           6          0      0      0    148     0   22
33        0       0        0       0       0           0          0      0      0     18     1   12
34        1       0      129       0       0           0          0      0      0     25     1   12
35        0       0        1       0       0           0          0      0      0      8     1   12
36        0       0        0       0       0           0          0      0      0      4     1   12
37        0       0        0       0       0           8          0      0      0     72     1   20
38        0       0        7       0       0           0          0      0      0      4     1   20
39        1       1       57       3       0           5          2      1      0    151     0   20
40        0       1       16       0       0           0          3      1      0     51     1   16

答案 2 :(得分:1)

C标准说:

  

在翻译单元集中每个特定的声明   具有外部链接的标识符表示相同的实体(对象或   功能)。在一个翻译单元内,每个声明一个   具有内部链接的标识符表示相同的实体。

在翻译单元集中,我们不能有多个具有相同名称的不同外部实体,因此表示该单个外部实体的每个声明的类型应该一致。我们可以在一个翻译单元中检查类型是否一致,这是在编译时完成的。我们无法在编译时或链接时检查不同翻译单元之间的类型是否一致。

  

对于使用存储类说明符extern声明的标识符   可以看到该标识符的先前声明的范围,31)   如果事先声明指定内部或外部联系,则   后面声明中标识符的链接与   在先前声明中指定的联系。如果没有事先声明   可见,或者如果先前的声明指定没有链接,那么   标识符有外部链接。

static int a; //a_Internal

int main(void) {
    int a; //No linkage
    {
        extern int a; //a_External
    }
    return 0;
}

此处标识符a的先前声明没有链接,因此extern int a具有外部链接。这意味着我们必须在另一个翻译单元中定义int。但是 GCC 决定拒绝使用之前声明的static重新声明的变量' extern'错误,可能是因为我们根据C标准有未定义的行为。