在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。


当前回答

我们有两个文件,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”,所以没有必要显式地指定它。

这并没有使这个关键字无用,因为它也可以与变量一起使用(在这种情况下-这是解决链接问题的唯一解决方案)。但是对于函数,是的,这是可选的。

我们有两个文件,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 i;

在C文件的文件范围内(函数块之外),那么你说“变量可能在其他地方定义”。

extern int f() {return 0;}

既是函数f的声明,也是函数f的定义。在这种情况下,定义覆盖了extern。

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

首先是声明,然后是定义。

如果您想声明和同时定义一个文件作用域变量,使用extern是错误的。例如,

extern int i = 4;

将给出一个错误或警告,这取决于编译器。

如果显式地希望避免定义变量,则使用extern非常有用。

让我解释一下:

假设文件a.c包含:

#include "a.h"

int i = 2;

int f() { i++; return i;}

文件a.h包括:

extern int i;
int f(void);

文件b.c包含:

#include <stdio.h>
#include "a.h"

int main(void){
    printf("%d\n", f());
    return 0;
}

The extern in the header is useful, because it tells the compiler during the link phase, "this is a declaration, and not a definition". If I remove the line in a.c which defines i, allocates space for it and assigns a value to it, the program should fail to compile with an undefined reference. This tells the developer that he has referred to a variable, but hasn't yet defined it. If on the other hand, I omit the "extern" keyword, and remove the int i = 2 line, the program still compiles - i will be defined with a default value of 0.

文件作用域变量是隐式定义的,如果没有显式地为它们赋值,则默认值为0或NULL——这与在函数顶部声明的块作用域变量不同。extern关键字避免了这种隐式定义,因此有助于避免错误。

对于函数,在函数声明中,关键字确实是多余的。函数声明没有隐式定义。

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

那么,代码:

    int f() {return 0;}

编译器将处理为

    extern int f() {return 0;}

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

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

希望这能回答你的问题。