【问题标题】:Initialization of extern variable warning in GCC (C18)GCC (C18) 中外部变量警告的初始化
【发布时间】:2020-08-27 12:35:50
【问题描述】:

问题不是“为什么我不能初始化声明为 extern 的变量”,因为文件范围变量完全可以实现(而不是块范围变量)。问题是 GCC 在这种特殊情况下会产生警告(使用-Wall 开关):

extern int n = 10;  // file scope declaration

GCC 产量:

test.c:5:12: warning: ‘n’ initialized and declared ‘extern’

不过,代码运行良好。

此外,请注意,以下定义绝对等同于第一个:

int n = 10;  // file scope declaration

在这两种情况下,变量具有相同的链接和存储类型。问题是,由于两者绝对等价,第二个版本在 GCC 中不会产生任何警告(使用 -Wall)。

这是为什么呢?

我的猜测是,您通常使用extern 显式设置一个提醒,即这是一个引用在别处定义的外部对象的声明,因此您不应该(尽管可以)初始化变量(请记住,该标准不允许您在同一链接内定义一个变量两次,在本例中为外部)。

那么,这是一个正确的猜测吗,或者可能还有更多,我看不到?

【问题讨论】:

  • 这是 GCC 的一个怪癖——它不是 C 的正常编写方式,编译器会生成警告。最简单的方法是在初始化变量时避免使用extern。对于旧版本的 C 标准,您会从 GCC 收到警告;它与 C18 无关。
  • 我认为这可以归结为“为什么?”。在什么情况下这样做很有用?请参阅 GCC Bugzilla 上 2010 年的 this post。上面的first comment 指出这是关于编码风格的,并将这种模式描述为“非常单一”。
  • 一些关于 extern 的 C 规则是一团糟,因为随着时间的推移,语言随着不同的实践而演变,导致允许某些事情,禁止其他事情,并赋予某些含义。编译器警告是这种混乱历史的结果。在非定义声明中而不是在定义中使用extern 是一种常见的做法,因此编译器会警告它在定义中的使用,但 C 标准允许这样做。
  • @th33lf 好吧,这个问题与禁用警告更相关,就像正在讨论的那样,没有特定的开关。

标签: c gcc


【解决方案1】:

编译器可以警告它喜欢的任何东西。如果它很专心,它会警告它认为“可疑”的事情。

这里就是这样。

我个人对推理的看法同意你的观点:

我的猜测是你通常使用extern 来明确设置一个提醒,即这是一个引用在别处定义的外部对象的声明,因此你不应该(尽管你可以)初始化变量(bear请记住,该标准不允许您在同一个链接中定义一个变量两次,在本例中为外部)。

GCC 发现初始化显式 extern 声明的变量是可疑的,因为通常更常见的是在一个文件中定义变量,然后在另一个文件中定义变量,这可能取决于上下文,导致链接错误,实际上可能是原因,但我们的假设并不值得。

关于实际“为什么”的问题,您需要询问 GCC 本身的实现者。

【讨论】:

  • 公平地说,extern 显然是多余的,并且没有添加任何语句。它没有害处,但也可以安全地省略。编译器还试图防止潜在的链接器错误,以防变量的实际定义存在于另一个翻译单元中。
【解决方案2】:

关键字extern用于声明一个变量但不定义它(类似于函数声明)。它通常用于头文件中以从模块中导出变量。但是,通常最好引入一个返回其值的函数。

例子:

M.h

extern int M_n;

M.c

int M_n = 10;

【讨论】:

  • 虽然您所说的是典型用途,但问题中显示的代码没有任何无效之处。对于extern,这只是一个不寻常的、不直观的用法。我主要对第一句话有疑问。
  • @ThomasJager 即使它是有效的,你为什么要这样做?使用 extern 的声明应该在头文件中,变量定义应该在实现文件中。
  • 有一个推荐的规则,一般来说,在多个翻译单元中使用的名称的非定义声明应该在标题中,而定义应该在源文件中。建议使用该规则因为标头用于使其他翻译单元知道名称(因此它们应该具有声明)并且在其中定义对象或函数会导致多个定义。你说使用extern 的声明应该在头文件中。为什么会有这样的规定?什么是“因为”导致这样的规则并说extern不应该在源文件中使用?
  • @AugustKarlstrom 我同意,这就是我在对这个问题的评论中提出的观点。但是,我觉得您的回答根本没有真正解决问题,只回答“extern 是什么?”。第一句暗示extern 的变量如果没有在另一个单元中创建存储空间,则不会给予任何存储空间。
  • @EricPostpischil 因为据我所知,实现文件中没有 extern 的用例。如果有,请告诉我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-06
  • 2017-11-24
  • 1970-01-01
相关资源
最近更新 更多