【问题标题】:Order of `static` definition and `extern declaration` in a translation unit翻译单元中“静态”定义和“外部声明”的顺序
【发布时间】:2013-08-09 07:41:30
【问题描述】:

我无法理解为什么这不起作用。

extern int i;

int main()
{
  printf(" %d ", i);  
}

static int i =3;

另外,这不起作用:

extern int i;

static int i =3;

int main()
{
  printf(" %d ", i);  
}

但如果 static 变量在 extern declaration 之前定义,它可以工作:

static int i =3;

extern int i;

int main()
{
  printf(" %d ", i);  
}

据我了解,extern int i告诉我i 存在于其他地方,这里看起来很像(int i

但是,其他地方的意思是:

1) 也许,稍后在 same 翻译单元中指向 global variable

2) 也许,在某些other 翻译单元中。

我认为(1) 将有效,即使static int i = 3 已将i 的范围限制为定义它的当前翻译单元。

static int i =3global(我的意思是至少它在翻译单元中可见)不是在这里,即使它的翻译单元的范围受到限制?那为什么编译器找不到呢?

当我编译前两个版本时,我得到以下编译时错误:

 error: static declaration of ‘i’ follows non-static declaration
 note: previous declaration of ‘i’ was here

我无法理解此错误消息。另外,为什么它抱怨它是静态的declaration 不是definition 吗?

【问题讨论】:

  • 究竟是什么“不起作用”?是编译问题吗?运行时问题?我正在用 VS 2010 编译你的代码,它似乎工作正常。
  • GCC 编译器,我得到一个编译时错误静态声明,我遵循非静态声明。

标签: c static extern


【解决方案1】:

C11 6.2.2 标识符的链接第 4 节

对于在一个范围内使用存储类说明符 extern 声明的标识符 该标识符的先前声明是可见的,31) 如果先前声明指定内部或外部链接,则后面声明的标识符链接与先前声明中指定的链接相同。如果前面的声明不可见,或者前面的声明没有指定链接,则标识符具有外部链接。

所以第二个声明将跟随第一个,回到您的示例,第一个和第二个示例i 将有一个extern 存储类。编译器认为这是一个错误。

在第三个示例中,i 将是 static,因为 static 首先显示。那应该没问题。

并且,在 C11 6.2.2 的第 7 节中 标识符的链接

如果在一个翻译单元中,相同的标识符同时出现在内部和外部 链接,行为未定义。

所以最好不要在同一个翻译单元中同时声明 staticextern 的同一个变量。

【讨论】:

  • 是的,我同意。但我仍然担心的是为什么3rd 版本always 有效?跨许多编译器。
  • @UchiaItachi:你为什么担心第三个版本?此答案引用了 C 标准中的解释文本:当 extern 声明遵循具有内部 (static) 或外部链接的声明时,使用前面的声明。
  • @UchiaItachi 一方面,即使您测试了所有显然无法测试的编译器,并且一切正常,但这并不意味着它是已定义的行为。标准是要决定的。
【解决方案2】:

嗯,变量是externstatic。请记住,全局级别的static 将其可见性限制为仅对当前翻译单元可见,而extern 则规定它在不同的翻译单元中可见。

【讨论】:

  • 我知道static 重新定义了可见性,extern 可以指示其他翻译单元 including 当前的翻译单元。但是如果我之前定义了静态变量并给出一个外部声明证明它具有staticextern,那么代码就可以工作。
  • 这实际上让我很困惑,但我唯一的解释是错误消息本身:static declaration of ‘i’ follows non-static declaration。据我了解,static 必须在任何非静态声明之前。当到达extern 时,已经有了extern 满意的i 的定义。
【解决方案3】:

将某些东西声明为static 并再次声明为extern 是没有意义的。这样做是未定义的行为,所以不要这样做。

【讨论】:

  • 但是为什么extern 声明不存在?要告诉它是在文件的下方定义的吗?而且我知道您的代码可以正常工作,正如我在问题中已经提到的那样。
  • @UchiaItachi,编辑了我的答案,现在是正确的。这是未定义的行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-10
  • 1970-01-01
相关资源
最近更新 更多