3

我试图了解 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任何地方添加吗?

4

4 回答 4

5
/* 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 文件中的那个),并且包含头文件的每个编译单元都将引用该定义。

于 2013-05-14T12:02:16.157 回答
1

如果你在头文件中声明你的变量并且有任何源文件也声明了这个相同的变量,每个编译单元都会有这个变量的不同实例。

在一个编译单元中声明它,并在你的头文件中添加一个“extern ...”将使所有编译单元访问相同的全局变量。

于 2013-05-14T11:47:50.273 回答
0
Does the above code operates with the same i variable everywhere?

是的。

Do I need to add externanywhere?

在本例中,不需要。因为MyCommonHeader.h在定义 i 的地方只包含一次。

在下面的例子中,extern更有用。

//main.c

#include <stdio.h>
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 并且只包含该标题。

于 2013-05-14T11:55:31.843 回答
0

在头文件中声明,然后将其包含在多个位置,最终会得到 i 的多个实例(并可能出现编译或链接问题)。因此最好在头文件中使用 extern 并将其定义在一个 .c 文件中.在此之后,您可以在不重复变量定义的情况下包含标题。

于 2013-05-14T11:59:24.573 回答