怀疑与外部关键字使用有关

AFAIK,extern关键字应该用于声明,并且没有值可以与使用extern关键字声明的变量相关联。 但是假设我写了一个类似的声明

extern int i = 10; 

编译器是否应标记错误? 我看到一些编译器容忍并忽略了这一点? 为什么会这样? ‘C’标准对此有何看法?

编辑:@All,谢谢你的回答。 我仍有疑问。 假设我有这个变量的定义而没有另一个文件中的extern链接说ac和我在bc中添加这个语句仍然可以编译器不标记错误吗? 它是否会被重新定义?

这是有效的语法,在C99标准中甚至有一个基本相同的例子。 (见§6.9.2-4。)

确实,这些例子不是规范性的,但我认为这是合法的语法。 编译器通常会输出一个警告,因为它并没有真正完成任何事情。

4例1

 int i1 = 1; // definition, external linkage static int i2 = 2; // definition, internal linkage extern int i3 = 3; // definition, external linkage int i4; // tentative definition, external linkage static int i5; // tentative definition, internal linkage int i1; // valid tentative definition, refers to previous int i2; // 6.2.2 renders undefined, linkage disagreement int i3; // valid tentative definition, refers to previous int i4; // valid tentative definition, refers to previous int i5; // 6.2.2 renders undefined, linkage disagreement extern int i1; // refers to previous, whose linkage is external extern int i2; // refers to previous, whose linkage is internal extern int i3; // refers to previous, whose linkage is external extern int i4; // refers to previous, whose linkage is external extern int i5; // refers to previous, whose linkage is internal 

以下代码;

 extern int i ; 

声明变量i,但不实例化它。 如果它也未在同一编译单元中定义,则链接器将尝试从包含最终可执行文件的目标文件和库中解析它。

但是你的例子:

 extern int i = 10 ; 

初始化对象,因此也必须实例化它。 在这种情况下, extern关键字是多余的,因为对象在同一个编译单元中初始化(实际上是相同的语句)。 它相当于:

 extern int i ; // redundant int i = 10 ; 

虽然在最后一个示例中,extern关键字是冗余的,但它完全等同于在头文件中声明全局变量时所拥有的,并且在包含该头的源文件中实例化 (因为它应该允许编译器)执行类型检查)。

您可以按如下方式测试:

 extern int i ; int main() { i = 10 ; } 

以上将导致未解析的变量i的链接器错误。 鉴于:

 extern int i = 10 ; int main() { i = 10 ; } 

将链接没有问题。

extern关键字表示给定变量在不同的模块中分配。 它与访问该变量无关。 分配给外部变量是完全合法的。

extern关键字的目的是为实体提供外部链接 。 无论是在声明中使用还是在定义中使用都没有区别。 您发布的代码绝对没有错误。

如果您更愿意根据“导出与导入”来考虑它,那么应用于非定义声明的 extern关键字意味着我们正在导入在其他一些翻译单元中定义的实体。 当extern关键字应用于定义时 ,意味着我们要导出此实体以供其他翻译单元使用。 (虽然值得注意的是“出口与import”并不是思考C联动概念的标准方式。)

您不会经常看到定义中使用的关键字的原因是因为在C文件范围定义中默认具有外部链接。 所以写作

 extern int i = 10; 

是有效的,但是多余的,因为它等同于普通的

 int i = 10; 

然而,在实际代码中,您可能会不时地看到人们将此关键字与函数声明和定义一起使用,即使它在那里也是多余的

 extern void foo(int i); /* `extern` is superfluous */ ... extern void foo(int i) /* `extern` is superfluous */ { /* whatever */ }