如何正确使用extern关键字在C

我的问题是关于在C语言中什么时候应该用extern关键字引用函数。

我看不出什么时候应该在实践中使用这种方法。当我在编写程序时,我使用的所有函数都可以通过我包含的头文件获得。那么为什么用extern来访问头文件中没有公开的内容是有用的呢?

我可能在思考extern如何不正确地工作,如果是这样,请纠正我。

也. .当它是头文件中没有关键字的默认声明时,你应该extern某些东西吗?

278987 次浏览

当你在不同的dll或lib上定义该函数时,编译器会根据链接器来查找它。典型的情况是当你从OS API调用函数时。

如果程序中的每个文件首先被编译为一个目标文件,然后目标文件被链接在一起,你需要extern。它告诉编译器“这个函数存在,但是它的代码在其他地方。不要惊慌。”

extern改变链接。使用关键字,函数/变量被假定在其他地方可用,解析被推迟到链接器。

extern在函数和变量上是不同的。

对于变量,它不实例化变量本身,即不分配任何内存。这得在别的地方做。因此,如果您想从其他地方导入变量,这是很重要的。

对于功能,这只告诉编译器链接是extern。因为这是默认值(使用关键字static表示函数没有使用extern链接绑定),所以不需要显式地使用它。

其他源文件中实际上定义的函数在头文件中只能是宣布。在这种情况下,当声明是头文件中的原型时,你应该使用走读生

大多数情况下,你的函数会是以下其中之一(更像是最佳实践):

  • static(正常的非静态函数 在.c文件外可见)
  • 静态内联(内联来自.c或.h 李文件)< / > 的头中的声明 Next kind(见下文))
  • [no keyword whatever](正常 用于访问的函数 李extern声明)< / >

头文件中所有函数和变量的声明都应该是extern

该规则的例外是头文件中定义的内联函数和变量,尽管在头文件中定义,但必须是翻译单元(头文件包含的源文件)的本地变量:这些应该是static

在源文件中,extern不应该用于文件中定义的函数和变量。只要给本地定义加上static前缀,而对共享定义什么都不做——默认情况下,它们将是外部符号。

在源文件中使用extern的唯一原因是声明在其他源文件中定义且没有提供头文件的函数和变量。


声明函数原型extern实际上是不必要的。有些人不喜欢它,因为它只会浪费空间,而且函数声明已经有溢出行限制的倾向。其他人喜欢它,因为这样,函数和变量可以以相同的方式处理。

在C语言中,extern对于函数原型是隐含的,因为原型声明了在其他地方定义的函数。换句话说,函数原型默认具有外部链接;使用extern是可以的,但这是多余的。

(如果需要静态链接,则函数必须在其原型和函数头中声明为static,并且这些通常都应该在相同的.c文件中)。

前面已经说过,extern关键字对于函数来说是多余的。

对于跨编译单元共享的变量,应该在头文件中使用extern关键字声明它们,然后在单个源文件中定义它们,不使用extern关键字。为了最佳实践,单个源文件应该是共享头文件名称的文件。

extern告诉编译器这个数据是在某个地方定义的,并且将与链接器连接。

在这里的回答和与一些朋友的交谈的帮助下,这里有一个使用extern的实际示例。

例1 -显示一个陷阱:

stdio.h:

int errno;

myCFile1.c:

#include <stdio.h>


// Code using errno...

myCFile2.c:

#include <stdio.h>


// Code using errno...

如果myCFile1.omyCFile2.o被链接,则每个c文件都有errno的单独副本。这是一个问题,因为相同的errno应该在所有链接的文件中可用。

例2 -修复。

stdio.h:

extern int errno;

stdio.c:

int errno;

myCFile1.c:

#include <stdio.h>


// Code using errno...

myCFile2.c:

#include <stdio.h>


// Code using errno...

现在,如果myCFile1.oMyCFile2.o都被链接器链接,它们将都指向相同的errno。因此,用extern解决实现问题。

一篇关于extern关键字的非常好的文章,以及示例:http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

虽然我不同意在函数声明中使用extern是多余的。这应该是一个编译器设置。因此,我建议在需要时在函数声明中使用extern

多年以后,我发现了这个问题。看完每个回答和评论后,我想我可以澄清一些细节……这可能对通过谷歌搜索来到这里的人有用。

这个问题是专门关于使用extern函数的,所以我将忽略对全局变量使用extern

让我们定义3个函数原型:

// --------------------------------------
// Filename: "my_project.H"
extern int function_1(void);
static int function_2(void);
int function_3(void);

头文件可以被主要源代码使用,如下所示:

// --------------------------------------
// Filename: "my_project.C"
#include "my_project.H"


void main(void) {
int v1 = function_1();
int v2 = function_2();
int v3 = function_3();
}


int function_2(void) return 1234;

为了编译和链接,我们必须在调用该函数的同一源代码文件中定义function_2。另外两个函数可以在不同的源代码*.C中定义,也可以位于任何二进制文件(*.OBJ*.LIB*.DLL)中,我们可能没有这些文件的源代码。

让我们再次在不同的*.C文件中包含头文件my_project.H,以更好地理解两者的区别。在同一个项目中,我们添加以下文件:

// --------------------------------------
// Filename: "my_big_project_splitted.C"
#include "my_project.H"


void old_main_test(void){
int v1 = function_1();
int v2 = function_2();
int v3 = function_3();
}


int function_2(void) return 5678;


int function_1(void) return 12;


int function_3(void) return 34;

需要注意的重要特性:

  • 当一个函数在头文件中定义为static时,编译器/链接器必须在每个使用该包含文件的模块中找到具有该名称的函数实例。

  • 作为C库一部分的函数只能在一个模块中通过在该模块中使用static重新定义原型来替换。例如,替换对mallocfree的任何调用,以添加内存泄漏检测功能。

  • 函数实际上不需要extern说明符。当static未找到时,函数总是假定为extern

  • 然而,extern不是变量的默认值。通常情况下,任何头文件都需要使用extern来定义跨多个模块可见的变量。唯一的例外是头文件被保证包含在一个且只有一个模块中。

    许多项目经理会要求将该变量放在模块的开头,而不是放在任何头文件中。一些大型项目,如视频游戏模拟器“Mame"甚至要求这些变量只出现在使用它们的第一个函数的上面。