是否应使用关键字external定义具有外部链接的变量?

时间:2016-10-26 01:36:46

标签: c language-lawyer

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

  

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

     

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

     

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

     

请注意:

     

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

     

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

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

  1. 在file1中,全局变量应使用关键字定义 extern

    上面的引言似乎与自相矛盾:

    • "在其他源代码中定义关键字时,必须使用关键字extern"似乎应该说它应该。

    • "任何全局对象默认外部链接"似乎说它并不需要。

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

3 个答案:

答案 0 :(得分:3)

tldr:您应该在头文件中声明带有extern的变量,该文件包含在file1和file2中。然后,您应该仅在file1中定义变量。要定义变量,请将其声明为,而不是 extern(并且没有static)。

听起来你已经获得了extern关键字和标准术语"外部链接"混淆了。

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

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

/* file1.c */
extern int foo;

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

他们的组合不是有效的计划。您将从链接器中收到错误,可能会读取类似"对foo"的未定义引用。

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

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

可以写

/* file1.c */
extern int foo;

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

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

答案 1 :(得分:1)

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时的不同行为。我找不到它。如果有人能证实那就太好了。

答案 2 :(得分:1)

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

  

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

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

可以在定义中包含冗余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"