AFAIK,extern 关键字应该用于声明,并且没有值可以与使用 extern 关键字声明的变量相关联。但是假设我写了一个像
extern int i = 10;
编译器是否应该标记相同的错误?我已经看到一些编译器容忍并忽略了这一点?为什么会这样?“C”标准对此有何评论?
编辑:@All,感谢您的回答。不过,我仍有疑问。假设我在另一个文件中定义了这个变量而没有外部链接,比如 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
是给实体外部链接。无论是在 a 或定义中的声明中使用它都没有区别。您发布的代码绝对没有错误。
如果您更愿意从“导出与导入”的角度来考虑它,那么extern
应用于非定义声明的关键字意味着我们正在导入在其他翻译单元中定义的实体。当extern
关键字应用于定义时,这意味着我们正在导出该实体以供其他翻译单元使用。(尽管值得注意的是,“导出与导入”并不完全是思考 C 链接概念的标准方式。)
您不会经常看到定义中使用的关键字的原因是因为在 C 文件范围定义中默认具有外部链接。所以写
extern int i = 10;
是有效的,但是是多余的,因为它等价于plain
int i = 10;
然而,在实际代码中,您可能会不时看到人们在函数声明和定义中使用这个关键字,即使它在那里也是多余的
extern void foo(int i); /* `extern` is superfluous */
...
extern void foo(int i) /* `extern` is superfluous */
{
/* whatever */
}