当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何在C中正确使用extern关键字》经验,为你挑选了7个好方法。

我的问题是关于何时应该用externC中的关键字引用函数.

我没有看到何时应该在实践中使用它.在我编写程序时,我使用的所有函数都通过我包含的头文件提供.那么为什么extern访问头文件中没有公开的东西会有用呢?

我可能会想到如何extern正确地工作,如果是这样,请纠正我.

编辑:如果extern是头文件中没有关键字的默认声明,你应该做些什么吗?



1> bluebrother..:

" extern"改变了联系.使用关键字,假定函数/变量在其他位置可用,并且解析将延迟到链接器.

函数和变量的"extern"之间存在差异:在变量上它不会实例化变量本身,即不分配任何内存.这需要在其他地方完成.因此,如果您想从其他地方导入变量,这很重要.对于函数,这只告诉编译器链接是extern.由于这是默认值(您使用关键字"static"来表示函数未使用extern链接绑定),因此您无需显式使用它.



2> lillq..:

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

在这里的回答的帮助下,在这里与几个朋友交谈是使用extern的实际例子.

示例1 -显示陷阱:

File stdio.h:

int errno;
/* other stuff...*/

myCFile1.c:
#include 

Code...

myCFile2.c:
#include 

Code...

如果链接了myCFile1.o和myCFile2.o,则每个c文件都有errno的单独副本.这是一个问题,因为所有链接文件中都应该提供相同的errno.

示例2 -修复.

File stdio.h:

extern int errno;
/* other stuff...*/

File stdio.c

int errno;

myCFile1.c:
#include 

Code...

myCFile2.c:
#include 

Code...

现在,如果链接器链接了myCFile1.o和MyCFile2.o,它们都将指向相同的errno.因此,用extern解决实现.


问题不在于myCFile1和myCFile2模块有一个单独的errno副本,而是它们都暴露了一个名为"errno"的符号.当链接器看到它时,它不知道要选择哪个"errno",因此它会以错误消息挽救.
@MarcelFalliere [Wiki](http://en.wikipedia.org/wiki/Linker_(computing))〜编译器自己编译每个源文件,并为每个源文件创建一个目标文件.链接器将这些目标文件链接到1个可执行文件
包括警卫不是保护这个确切的事情吗?
"链接器链接"实际意味着什么?大家都用这个词,我找不到任何定义:(

3> aib..:

已经声明extern关键字对于函数来说是多余的.

对于在编译单元之间共享的变量,您应该在带有extern关键字的头文件中声明它们,然后在单个源文件中定义它们,而不使用extern关键字.单个源文件应该是共享头文件名称的文件,以获得最佳实践.



4> Steve Melnik..:

在C中,'extern'隐含在函数原型中,因为原型声明了一个在其他地方定义的函数.换句话说,函数原型默认具有外部链接; 使用'extern'很好,但是多余.

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



5> Christian Gi..:

许多年后,我发现了这个问题.在阅读了每个答案和评论后,我虽然可以澄清一些细节......这对于通过护目镜搜索来到这里的人来说非常有用.

问题是关于使用"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;

需要注意的重要特性:当函数在头文件中定义为"静态"时,编译器/链接器必须在每个使用该包含文件的模块中找到具有该名称的函数的实例.

通过仅在该模块中使用"静态"重新定义原型,可以仅在一个模块中替换作为C库的一部分的功能.例如,替换对"malloc"和"free"的任何调用以添加内存泄漏检测功能.

函数并不真正需要说明符"extern".如果未找到"静态",则始终假定函数为"extern".

但是,"extern"不是变量的默认值.通常,任何定义要在多个模块中可见的变量的头文件都需要使用"extern".唯一的例外是如果保证头文件只包含在一个模块中.

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


如果在第100行调用函数并在第500行实例化,则需要定义.第100行将声明未定义的原型.因此,您将原型添加到顶部附近.

6> tozak..:

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

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


在我来到这里之前,我已经阅读了geeksforgeeks.org的文章,但发现写得很糟糕.除了语法和语法上的缺点之外,它使用了很多单词来多次制作相同的点,然后浏览关键信息.例如,在例4中,突然包含'somefile.h',但除了以下内容之外没有任何内容:"假设somefile.h具有var的定义".好吧,我们"假设"的信息恰好是我正在寻找的信息.不幸的是,这个页面上的答案都不是更好.

7> Chris Lutz..:

如果程序中的每个文件首先编译为目标文件,则需要将目标文件链接在一起extern.它告诉编译器"这个函数存在,但它的代码在别的地方.不要惊慌."

推荐阅读
coco2冰冰
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有