C语言中全局变量的定义及重复包含问题

C语言学习笔记 专栏收录该内容
1 篇文章 0 订阅

C语言中全局变量的定义及重复包含问题

         C语言中一般将全局变量intA的定义和初始化放在fileName .c或者其它 xx.c文件中,同时在与之对应的fileName.h文件中进行 extern int A声明。当一个全局变量int A仅在fileName.c文件中定义而未在相对应的头文件fileName.h声明时,包含与之相应的fileName.h文件时编译器会出现未定义的错误,其原因是编译器在fileName.h里面找不到该变量的说明。如:

例1

/*file1.h*/

#ifndef _ FILE1_H

#define _FILE1_H

/*…………………*/

 

#endif

/*file1.c*/

int A=0;

 

/*main.c*/

#include “file1.h”

int main(int argc,char** argv){

         A=123;

         return0;

}

 

此时编译器在预处理的时候会把整个file1.h文件在#include “file1.h”处展开。当读到A=123的时候在file1.h查找不到有关A的声明或定义,所以会报“未声明标识符A”的错误。

         那么如果直接将全局变量直接定义在头文件中,此时编译器会识别到变量A吗?答案是肯定的。但是为什么没有人这么做呢?那就看看在将全局变量定义在头文件中会发生什么事情?

例2:

假设有头文件fileA.h  源文件fileA.c    main.c

/*fileA.h*/

#ifndef _FILE_A_H

#define _FILE_A_H

int gva =123;

#endif

 

/*fileA.c*/

#include “fileA.h”

 

/*…………..*/

 

/*main.c*/

#include <stdio.h>

#include <stdlib.h>

 

#include “fileA.h”

 

int main(int argc,char** argv){

         gva=456;

         return 0;

}

 


开始编译,这时会发现编译器报错了:提示为:“main.obj: error LNK2005: _gva 已经在fileA.obj中定义,fatalerror LNK1169: 找到一个或多个多重定义的符号”。可是明明已经做了避免重复包含的处理,为什么会出现这种情况呢?原因在于C语言编译的时候首先会进行单个.c文件的编译,然后再进行连接。避免重复包含只能保证在单个 .c编译的时候不被重复编译,而不能保证多个.c编译的时候不会被重复编译。什么意思?以上面的代码为例,如果另有头文件 B.h C.h 其中  B.h里面有

 #include “fileA.h”

 C.h里面有 

#include “B.h”

 #include  “fileA.h”

 

上面提到过#include 是在预处理的时候将该头文件在当前位置展开,此时在编译C.c文件的时候,编译的时候会先将#include “B.h”代码段展开编译,而B.h里面包了fileA.h所以fileA.h已经编译了,此时_FILE_A_H的值已经为1,当展开#include “fileA.h” 时因为_FILE_A_H已经定义,所以会自动跳过#endif处,避免重复包含的预算理起了作用,会跳到#endif处。

         回到 例2 因为单个.c文件的编译是独立进行的,首先编译fileA.c 到fileA.obj。然后编译main.c 到main.obj。此时的编译是没有问题的,接下来进行目标文件链接,此时编译器就会发现fileA.obj中为变量vga分配了内存空间,而在main.obj中也为vga分配了内存空间。这时变量 vga就有两个不同的变量地址,编译器不知道该哪个才是gva的地址。

         为什么有的人在头文件中使用了static 后会顺利通过编译呢。static关键字修饰的变量会延长其生存周期,但是也限定在该变量只在当前文件中可见,相当于在编译的时候又定义了一个新的变量而变量名相同而已(类似于两个函数内的局部变量关系,只作用于当前函数)。所以严格意义来说static 修饰的变量尽管定义在函数外面但不能算是全局变量。

 

 

  • 4
    点赞
  • 0
    评论
  • 4
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值