【问题标题】:Shall an variable with external linkage be defined with keyword external?是否应该使用关键字 external 定义具有外部链接的变量?
【发布时间】:2016-10-26 01:36:46
【问题描述】:

来自https://www.quora.com/What-are-the-types-of-linkages-in-C-programming

外部链接,意味着可以在某处定义变量 else 在您正在处理的文件之外,这意味着您可以定义 它在任何其他翻译单元中,而不是您当前的翻译单元中(you 在另一个中定义时必须使用关键字 extern 源代码)。

内部链接,意味着变量必须在你的 翻译单元范围,这意味着它应该在任何 包含的库,或在同一文件范围内。

无链接,指向默认函数和大括号范围,例如 在函数内部定义一个自动变量,这将使 变量只能在该函数的范围内访问。

注意:

默认情况下,任何全局对象都是外部链接的,您可以使用关键字 static 禁用它。

默认情况下,任何常量全局对象都是内部链接的,你可以 使用关键字 extern 禁用它。

假设在file1中定义了一个全局变量,我想在file2中使用它。

  1. 在file1中,全局变量是否用关键字定义 extern?

    上面的引用似乎自相矛盾:

    • “在其他源代码中定义时必须使用关键字 extern”似乎应该这样说。

    • “任何全局对象默认都是外部链接的”好像是说不需要。

  2. 在file2中,我应该用关键字extern声明全局变量吗?

【问题讨论】:

  • 我认为这两种情况都不是强制性的。第一句话可能恰好是错误的。让我检查一下标准
  • 一个是外联,一个是外联。我认为有不同。
  • 定义变量的地方需要使用extern的说法不正确。您只需要在文件中使用 extern 来引用在别处定义的变量。
  • @AndySchweig 我不同意。如果使用内部链接定义变量,则需要在定义变量的同一单元中使用extern
  • @DmitriChubarov 您的评论毫无意义;不能使用内部链接定义变量并且具有extern

标签: c language-lawyer


【解决方案1】:

tldr:您应该在文件1 和文件2 都包含的头文件 中声明变量extern。然后,您应该定义 file1 中的变量。要定义变量,你声明它没有extern(也没有static)。


您听起来好像混淆了extern 关键字和标准术语“外部链接”。

程序中的任何函数都可以访问具有“外部链接”的变量,只要该变量的声明对该函数可见。相比之下,具有“内部链接”的变量最多可以从一个“翻译单元”(单个源文件及其包含的所有文件)访问,而具有“无链接”的变量仅在单个函数中可见. (我不记得在函数中声明的 static 变量是否被认为具有内部链接或没有链接。)

应用于变量声明的extern 关键字具有两个 效果。首先,它保证该变量将被赋予外部链接,即使声明在函数内部(不要那样做)。其次,更重要的是,它使声明不是定义。这意味着,如果你有这两个文件

/* file1.c */
extern int foo;

/* file2.c */
extern int foo;
int main(void) { return foo; }

他们的组合不是一个有效的程序。你会从链接器中得到一个错误,可能会读到类似“undefined reference to foo”的内容。

要使其成为有效程序,您必须从foo 的两个声明中的一个 中删除extern。该声明然后成为定义,程序将链接。 (此外,如果您希望它在启动时具有 0 以外的值,则可以为该声明提供一个初始化器。)

如果您从foo 的定义的两个 中删除extern,则结果是IIRC,实现定义。一些 C 编译器会将它们合并到一个全局变量中,而其他编译器会发出链接时错误。有时行为取决于变量是否具有初始化器。

可以写

/* file1.c */
extern int foo;

/* file2.c */
extern int foo;
int foo;

这允许您将extern 声明放在两个.c 文件都包含的头文件中,这降低了声明类型不一致的风险(如果发生这种情况,程序将表现出未定义的行为)。

【讨论】:

  • 您能否澄清一下 define 与 declare 相比是什么意思?
  • @HuStmpHrrr 修改后的答案是否足够清楚?
【解决方案2】:

c11 草案,6.2.2,第 4 节,声明:

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

我不认为有或没有extern 关键字会有任何区别。一些实验还表明:

以下 2 编译:

extern int a;
extern int a;

int a = 20;

extern int a;
int a;

int a = 20;

但不是这个:

extern int a;
int a = 10;

int a = 20;

然而,我有一些印象,一旦我读到动态链接涉及 Windows 时的不同行为。我找不到它。如果有人能确认就好了。

【讨论】:

    【解决方案3】:

    你引用的文字有很多错误。我建议不要依赖该网站的信息。

    (在其他源代码中定义时必须使用关键字extern)。

    不正确,因为文件范围定义具有外部链接,除非使用了 static 关键字(或者没有使用说明符,并且它们正在重新声明已经使用 static 关键字声明的内容)。

    可以在定义中包含一个多余的extern,但是还必须有一个初始化器(否则它将是一个声明而不是定义)。

    内部链接,意味着变量必须在翻译单元范围内定义,这意味着它应该在任何包含的库中定义,或者在相同的文件范围内。

    大概这意味着“包含的标头”,而不是“包含的库”。

    默认情况下,任何常量全局对象都是内部链接的,您可以使用关键字 extern 禁用它。

    这是错误的,除非用static 声明,否则“全局对象”具有外部链接。作者可能将 C 与 C++ 混为一谈(在后者中,const 全局对象具有内部链接,除非另有说明)。


    假设在file1中定义了一个全局变量,我想在file2中使用它。

    // file1.h (or any other header)
    extern object_t obj;
    
    // file1.c
    #include "file1.h"
    object_t obj;   // or: extern object_t obj = { 1, 2, 3 };
    
    // file2.c
    #include "file1.h"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-29
      • 2011-07-31
      • 1970-01-01
      • 2016-08-25
      相关资源
      最近更新 更多