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

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

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

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

标题“MyCommonHeader.h”包含:

 //MyCommonHeader.h int* i; //pointer to an int 

文件MyFirstHeader.h包含:

 //MyFirstHeader.h void changeIt(int newValue); 

文件MyFirstSource.c包含:

 //MyFirstSource.c #include "MyFirstHeader.h" void changeIt(int newValue) { *i = newValue; } 

文件MySecondSource.c包含:

 //MySecondSource.c #include "MyCommonHeader.h" #include "MyFirstHeader.h" void main() { i = malloc(sizeof(int)); changeIt(10); *i = 23; } 

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

 /* file.h */ int* i; 

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

作为一种常见的扩展,编译器会跨翻译单元扩展此行为。 这意味着,对于这样的编译器,您可以安全地将该头文件包含在您想要的任意数量的翻译单元中,并且仍然只有i一个定义。

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

 /* file.h */ int* i = 0; 

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

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

 /* file.h */ extern int* i; /* file.c */ int* i = 0; 

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

如果在标头中声明变量并且任何源文件也声明同一个变量,则每个编译单元将具有此变量的不同实例。

在一个单独的编译单元中声明它,并在标题中添加“extern …”将使所有编译单元访问相同的全局变量。

在一个头文件中声明然后包含在多个地方,你最终会得到i的多个实例(并且可能会编译或链接问题)。所以在头文件中使用extern并在一个.c文件中定义它是个更好的主意。 。之后,您可以在不重复变量定义的情况下包含标题。

 Does the above code operates with the same i variable everywhere? 

是。

 Do I need to add externanywhere? 

在这个例子中,不需要。 因为MyCommonHeader.h只包含一次定义i。

在以下示例中, extern更有用。

 //main.c #include  int globaldata; int main() { .. } //Includes.h extern int globaldata; //Feature1.c #include "Includes.h" int func() { globaldata++; } //Feature2.c #include "Includes.h" int func_new() { globaldata = globaldata * 100; } 

globaldata是feature1.c和feature2.c使用的全局变量。 如果您定义该变量,那么它将是错误,如多个声明错误。

所以在这个scnario中总是使用extern,并且只包含头文件。