在C中,我没有注意到在函数声明之前使用extern关键字的任何影响。 首先,我认为当定义extern int f();在单个文件中强制您在文件范围之外实现它。然而,我发现:

extern int f();
int f() {return 0;}

and

extern int f() {return 0;}

编译正常,没有来自gcc的警告。我使用gcc -Wall -ansi;它甚至不接受//注释。

在函数定义之前使用extern有什么影响吗?或者它只是一个可选的关键字,对函数没有副作用。

在后一种情况下,我不明白为什么标准设计师选择用多余的关键字乱扔语法。

编辑:为了澄清,我知道在变量中有extern的用法,但我只问函数中的extern。


当前回答

在C语言中,函数隐式定义为extern,而不管是否实际声明关键字。

那么,代码:

    int f() {return 0;}

编译器将处理为

    extern int f() {return 0;}

从本质上讲,典型的函数定义与前面带有extern关键字的函数定义之间没有语义上的区别,如本例中所示。你可以在https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/上阅读更深入的解释

其他回答

内联函数对于extern的含义有特殊的规则。(注意,内联函数是C99或GNU扩展;他们不是原始的C。

对于非内联函数,不需要extern,因为默认情况下它是打开的。

注意,c++的规则是不同的。例如,在要从c++调用的C函数的c++声明上需要extern“C”,关于内联有不同的规则。

声明一个函数extern意味着它的定义将在链接时被解析,而不是在编译期间。

与没有声明extern的常规函数不同,它可以在任何源文件中定义(但不能在多个源文件中定义,否则会得到链接器错误,提示您已经给出了函数的多个定义),包括声明了extern的那个源文件。因此,在我们的例子中,链接器在同一个文件中解析函数定义。

我不认为这样做会很有用,但是做这样的实验可以更好地了解语言的编译器和链接器是如何工作的。

我们有两个文件,foo.c和bar.c。

这是foo.c

#include <stdio.h>

volatile unsigned int stop_now = 0;
extern void bar_function(void);

int main(void)
{
  while (1) {
     bar_function();
     stop_now = 1;
  }
  return 0;
}

这是bar。c

#include <stdio.h>

extern volatile unsigned int stop_now;

void bar_function(void)
{
   if (! stop_now) {
      printf("Hello, world!\n");
      sleep(30);
   }
}

正如你所看到的,foo.c和bar.c之间没有共享头文件,但是bar.c在被链接时需要在foo.c中声明的东西,而foo.c在被链接时需要bar.c中的函数。

通过使用'extern',你告诉编译器,在链接时,它后面的任何内容都将被找到(非静态);不要在当前通道中为它保留任何东西,因为它将在以后遇到。函数和变量在这方面是平等对待的。

如果你需要在模块之间共享一些全局,而不想把它放在/初始化在一个头文件中,它是非常有用的。

从技术上讲,库公共标头中的每个函数都是“extern”,但根据编译器的不同,将它们标记为“extern”几乎没有任何好处。大多数编译器可以自己解决这个问题。如你所见,这些函数实际上是在其他地方定义的。

在上面的例子中,main()只打印一次hello world,但继续输入bar_function()。还要注意,bar_function()在本例中不会返回(因为这只是一个简单的示例)。想象一下stop_now在信号被服务时被修改(因此是volatile),如果这看起来不够实际的话。

对于信号处理程序、一个你不想放在头文件或结构中的互斥量等,extern非常有用。大多数编译器会优化以确保它们不为外部对象保留任何内存,因为它们知道它们将在定义对象的模块中保留内存。但是,同样,在创建公共函数原型时,使用现代编译器指定它没有什么意义。

它没有效果的原因是在链接时,链接器试图解析extern定义(在您的例子中是extern int f())。它是在同一个文件中找到它还是在不同的文件中找到它并不重要,只要找到了它。

希望这能回答你的问题。

在C语言中,函数隐式定义为extern,而不管是否实际声明关键字。

那么,代码:

    int f() {return 0;}

编译器将处理为

    extern int f() {return 0;}

从本质上讲,典型的函数定义与前面带有extern关键字的函数定义之间没有语义上的区别,如本例中所示。你可以在https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/上阅读更深入的解释