在使用C语言编写程序时,经常会遇到这样的情况:我们希望在头文件中定义一个全局变量,并将其包含在两个不同的C文件中,以便这个全局变量可以在这两个文件中共享。举个例子,假设项目文件夹"project"下有三个文件:main.c、common.c和common.h。在这种情况下,我们希望声明一个字符型变量"key",使其在main.c和common.c中都可以被使用。
一种方法是在common.h文件中声明一个unsigned char类型的变量"key",然后由于main.c和common.c都包含了该头文件,因此这个"key"变量在两个文件中都是可见的,从而实现了共用。
回想起来确实有道理,但实际上在编写代码时,我们发现编译器给出了错误提示,大致是这样的:错误:L6200E:符号key重复定义(由common.o和main.o定义)。这意味着编译器认为我们重复定义了名为"key"的变量。造成这个问题的原因是#include命令会直接将头文件中的内容复制到#include的位置,导致main.c和common.c中都有了一份unsigned char key的定义。在C语言中,全局变量在整个项目(或称为工程)内都是可见的,因此项目中就存在了两个名为"key"的变量,编译器因此判定为重复定义。
正确的解决方法是使用extern关键字来声明变量为外部变量。具体做法是在其中一个c文件中定义全局变量"key",然后在另一个需要使用"key"的c文件中使用extern关键字进行声明,表明这个变量是在其他c文件中定义的全局变量。请注意我在这里所用的术语:定义和声明。例如,在main.c文件中定义变量"key",然后在common.c文件中使用extern关键字声明"key"为外部变量,这样这两个文件就能共享同一个变量"key"了。
(1)main.c文件
```c
#include "common.h"
unsigned char key_value;
```
(2)common.c文件:
```c
#include "common.h"
extern unsigned char key_value;
```
其实这就是变量定义和变量声明的区别。变量定义使用“数据类型+变量名称”的形式,编译器需要为其分配内存空间。而变量声明使用“extern 变量类型+变量名称”的形式,是告诉编译器该变量将在其他外部c文件中定义,此处只是引用它。编译器不会为其分配内存空间,直到遇到真正的变量定义时才会分配。
1、将普通变量定义为全局变量
如果是普通类型的变量,完全可以不使用*.h文件,在*.c文件中直接定义它,在调用该变量的文件中使用extern关键字进行声明。因为对于普通类型的变量,编译器是可以识别的。例如,在my.c文件中,我定义了一个char类型的数组name[10],那么在其他文件中只需使用extern char name[](由于是声明,数组的大小可以省略,但不建议使用指针,因为指针和数组有所不同)进行外部声明。这告诉编译器这个变量我已经定义过了,在其他地方具体怎样定义,你慢慢找吧。
2、将自定义结构体类型定义为全局变量
与普通类型不同,编译器不会自动识别我们自定义的类型,除非我们预先告知编译器。在这种情况下,头文件*.h的出现就很重要了。为了避免结构体类型占用额外的内存,我们可以将大结构体的定义放在*.h文件中。这样,无论多少次引用该头文件,内存都不会重复占用。而且这样做还有一个好处,其他文件可以通过include这个*.h文件,使得编译器可以识别我们的自定义类型。这样,我们就达到了预期的目的。
typedef struct _POSITION
int x;
int y;
}POSITION;
那么我可以在一个global.c文件中实现全局变量的定义,不过要include那个*.h文件,比如
/* ***global.c ******* */
include “global.h”
POSITION current,;
这样就定义了cunrrent这个变量,在别的文件中引用这个变量时,只要extern POSITION current;进行声明,然后就可以用了,不过这个文件也还得include "global.h" 因为如果不包含,在这个文件中是不识别POSITION类型的。
1.如何引用一个已经定义过的全局变量?
回答:可以通过引用头文件的方式,也可以使用extern关键字。如果通过引用头文件方式来引用头文件中声明的全局变量,假设我们在引用时出现了拼写错误,编译期间会报错,但如果我们使用extern关键字引用时出现了同样的错误,编译期间不会报错,而是在连接期间才会报错。
2.全局变量可不可以在多个.C文件中定义?为什么?
回答:可以。在不同的C文件中,可以用static关键字来声明同名的全局变量。虽然可以在不同的C文件中声明同名的全局变量,但前提是其中只能有一个C文件对该变量赋予初值,否则会在连接时报错。
————————————————
原文链接:https://blog.csdn.net/2301_76460576/article/details/132082437