我知道C中的全局变量有时有extern关键字。什么是extern变量?申报是什么样的?它的范围是什么?

这与跨源文件共享变量有关,但这究竟是如何工作的呢?我在哪里使用extern?


当前回答

Extern关键字与变量一起使用,以将其标识为全局变量。

它还表示可以使用使用extern声明的变量 关键字在任何文件中,尽管它在其他文件中声明/定义。

其他回答

Extern的使用使得一个first.c文件可以完全访问另一个secondc文件中的全局参数。

extern可以在first.c文件中声明,也可以在first.c包含的任何头文件中声明。

对于xc8,必须小心声明变量 在每个文件中都是相同的类型, 在一个文件中声明int型,在另一个文件中声明char型。 这可能会导致变量的破坏。

这个问题在大约15年前的一个微芯片论坛上得到了优雅的解决 /*参见“http:www.htsoft.com”/ /“论坛/ / showflat.php /猫/ 0 /数字/ 18766 / / /页面/ 0 # 18766”

但这种联系似乎不再起作用了……

所以我很快就会解释一下; 创建一个名为global.h的文件。

在其中声明以下内容

#ifdef MAIN_C
#define GLOBAL
 /* #warning COMPILING MAIN.C */
#else
#define GLOBAL extern
#endif
GLOBAL unsigned char testing_mode; // example var used in several C files

现在在文件main.c中

#define MAIN_C 1
#include "global.h"
#undef MAIN_C

这意味着在main.c中变量将被声明为unsigned char。

现在在其他文件中简单地包括global.h将 将其声明为该文件的extern。

extern unsigned char testing_mode;

但是它将被正确地声明为unsigned char。

旧的论坛帖子可能解释得更清楚一点。 但在使用编译器时,这是一个真正的潜在问题 这允许您在一个文件中声明一个变量,然后在另一个文件中将其声明为不同的类型。这些问题与 也就是说,如果你在另一个文件中将testing_mode声明为int类型 它会认为它是一个16位的变量,并覆盖ram的其他部分,可能会破坏另一个变量。很难调试!

简而言之,extern意味着变量是在其他模块中定义的,它的地址在链接时是已知的。编译器不会在当前模块中保留内存,并且知道变量类型。要理解extern,至少要有很少的汇编经验。

extern的正确解释是,你告诉编译器一些东西。你告诉编译器,尽管现在不存在,但声明的变量将以某种方式被链接器找到(通常在另一个对象(文件)中)。链接器将幸运地找到所有内容并将其组合在一起,无论是否有一些外部声明。

GCC ELF Linux实现

其他答案已经涵盖了语言使用方面的观点,所以现在让我们看看它是如何在这个实现中实现的。

c

#include <stdio.h>

int not_extern_int = 1;
extern int extern_int;

void main() {
    printf("%d\n", not_extern_int);
    printf("%d\n", extern_int);
}

编译和反编译:

gcc -c main.c
readelf -s main.o

输出包含:

Num:    Value          Size Type    Bind   Vis      Ndx Name
 9: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 not_extern_int
12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND extern_int

System V ABI Update ELF规范“符号表”章节解释:

这个节表索引表示该符号未定义。当链接编辑器将这个目标文件与另一个定义指定符号的文件结合在一起时,这个文件对符号的引用将被链接到实际的定义。

这基本上是C标准赋予extern变量的行为。

从现在开始,制作最终程序是链接器的工作,但是extern信息已经从源代码中提取到目标文件中。

在GCC 4.8上测试。

c++ 17内联变量

在c++ 17中,你可能想要使用内联变量而不是extern变量,因为它们使用简单(可以在头文件中定义一次)并且更强大(支持constexpr)。参见:“const static”在C和c++中是什么意思?