全局变量的C隐式extern,它什么时候发生,它是如何工作的

Shi*_*gon 3 c global-variables extern

我试图了解在多个文件(编译单元)之间共享 C 全局变量的方式。我读过优秀的问题和答案在这里。然而,在做了一些测试之后,我仍然有一些我没有得到的东西:

基本上我的问题是:如果在没有extern关键字的头文件中声明(但未定义)一个变量,是否可以简单地将该头文件包含在各种编译单元中,以便使该变量可用于所有这些编译单元?在这种情况下,这意味着一个(并且只有一个)编译单元包含用于初始化(定义?)该变量的代码,并且在其他编译单元尝试对该变量执行任何操作之前,它将首先被调用。如果这一切都是真的,那么这个过程是否称为“隐式外部”?

我将用一个例子来说明我的问题:

标题“MyCommonHeader.h”包含:

//MyCommonHeader.h
int* i; //pointer to an int
Run Code Online (Sandbox Code Playgroud)

文件 MyFirstHeader.h 包含:

//MyFirstHeader.h
void changeIt(int newValue);
Run Code Online (Sandbox Code Playgroud)

文件 MyFirstSource.c 包含:

//MyFirstSource.c
#include "MyFirstHeader.h"

 void changeIt(int newValue) {
    *i = newValue;
 }
Run Code Online (Sandbox Code Playgroud)

文件 MySecondSource.c 包含:

//MySecondSource.c
#include "MyCommonHeader.h"
#include "MyFirstHeader.h"

void main() {
   i = malloc(sizeof(int));
   changeIt(10);
   *i = 23;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码是否到处都使用相同的 i 变量?我需要在extern任何地方添加吗?

San*_*ker 5

/* file.h */
int* i;
Run Code Online (Sandbox Code Playgroud)

i变量的暂定定义。这意味着如果翻译单元中没有该变量的其他(外部)定义,它将只定义一次(初始化为0)。如果i翻译单元中的其他地方正好有一个匹配的(外部)定义,则将使用该定义,并且上面的暂定定义将表现为声明。

作为一种常见的扩展,编译器在翻译单元之间扩展了这种行为。这意味着,对于此类编译器,您可以安全地在任意数量的翻译单元中包含该头文件,并且仍然只有一个i.

如果您还在i头文件中显式初始化,情况会有所不同:

/* file.h */
int* i = 0;
Run Code Online (Sandbox Code Playgroud)

这是一个实际的定义(不是暂定的),您只能在一个编译单元中包含该头文件,否则您会得到多个定义错误。

更好的方法是在 .c 文件中定义变量,并extern在头文件中使用:

/* file.h */
extern int* i;

/* file.c */
int* i = 0;
Run Code Online (Sandbox Code Playgroud)

这绝对清楚地表明只有一个定义(.c 文件中的那个),并且包含头文件的每个编译单元都将引用该定义。