C语言中函数定义中extern关键字的含义引起了困惑

9
可能是重复的:
`extern`关键字对C函数的影响 好的,我已经花了几个小时阅读了大量关于`extern`关键字的含义的信息。有一件事情让我困扰不已,我找不到任何相关信息。 据我所知,`extern`关键字基本上告诉编译器变量或函数只是一个声明,并且它在某个地方被定义,因此编译器不必担心这个问题,链接器会处理它。
当输入以下内容时,编译器(我使用的是gcc 4.2.1)生成的警告:
extern int var = 10;

支持这一点。使用 extern,应该只是一个声明,所以它是不正确的。

然而,让我困惑的是,当输入以下内容时,没有任何警告或提示:

extern int func() {return 5;}

这是一个定义,应该生成相同的警告,但它没有。我在这里能找到的唯一解释是,定义覆盖了 extern 关键字。然而,按照这个逻辑,为什么它不会在变量定义时覆盖呢?或者说,关键字在与变量一起使用时有特殊含义吗?
如果有人能解释一下这个问题,我将非常感激。谢谢!

3
最后一个分号让我感到困扰。 - Seçkin Savaşçı
1
看看这个链接是否有帮助:https://dev59.com/I3RA5IYBdhLWcg3wtwSe。 - David Duncan
1
问题可能出在变量的初始化上。 - nabroyan
虽然这个问题名义上是一个重复的问题,但是在原始提出的被接受的答案质量很低。它过于冗长、不清晰、不完全准确,并且提供了无关的误导性建议。 - Eric Postpischil
2个回答

5

extern关键字只有在与变量一起使用时才具有特殊含义。在函数原型中使用extern完全是可选的:

extern void foo(int bar);

等同于

void foo(int bar);

当你声明/定义一个函数时,有两个选项:
1. 仅提供声明(即原型);或者 2. 提供定义,在没有原型的情况下也作为声明。
然而,对于变量,你有三个选项:
1. 仅提供声明; 2. 提供带有默认初始化程序的定义:int var;,不包括=10部分;或者 3. 提供带有特定初始化程序的定义:int var = 10
由于函数只有两个选项,编译器可以在不使用extern关键字的情况下区分它们。任何没有static关键字的声明都会被默认视为extern。因此,在所有函数声明或定义中,extern关键字都被忽略。
然而,对于变量,需要使用该关键字来区分#1和#2。当你使用extern时,它是#1;当你不使用extern时,它是#2。当你尝试将extern添加到#3时,会出现警告,因为它仍然是一个定义,extern会被忽略。
所有这些都有点简化:你可以在同一编译单元中多次提供声明,并且可以在全局范围或块范围内提供声明。有关完整细节,请查看C标准的6.7.9 5节。

关于对象(不是变量)声明的陈述是不正确的。在文件作用域中:int x; 是具有外部链接的对象的尝试性定义,extern int x; 是具有外部链接的对象的声明,int x = 3;extern int x = 3; 都是具有外部链接的对象的定义。在块作用域中:int x; 是没有链接的对象的定义,extern int x; 是具有外部链接的对象的声明,int x = 3; 是没有链接的对象的定义,而 extern int x = 3; 在 C 2011 6.7.9 5 中是不允许的。 - Eric Postpischil
以上假设每个声明都是标识符在该范围内第一次出现。否则,会有复杂情况。例如,static int x; extern int x; 是允许的,后者 x 与前者 x 相同。此外,尽管一些编译器对于文件作用域下的 extern int x = 3; 发出警告,但它在 C 2011 6.9.2 4 的示例中被明确显示为有效。 - Eric Postpischil

3
然而,按照这种逻辑,为什么在变量定义时它没有覆盖它?或者说这个关键字在与变量一起使用时有特殊意义吗?
变量和函数之间的区别在于:
void foo();

是一个函数声明,但

int i;

变量定义是指给变量赋予特定类型和名称的过程。

如果你在多个文件中都有相同的变量定义,那么编译器会为该变量生成多个存储空间(很可能导致链接错误)。但是对于函数则不是这样的情况。


1
我认为最令人困惑的是 extern int x = 1;,它看起来既像一个声明又像一个带有初始化器的定义。 - Alexey Frunze
在文件作用域中,“int i;”是一个试探性的定义,而不是一个定义,它既不会多次生成存储空间,也不会引起链接错误。 - Eric Postpischil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接