`

关于头文件定义全局变量等问题 (转载)

 
阅读更多
全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
可以,在不同的C文件中以static形式来声明同名全局变量。头文件中不可以直接定义变量和函数,但是可以定义static变量 ,类。
extern 用法,全局变量与头文件(重复定义)
用#include可以包含其他头文件中变量、函数的声明,为什么还要extern关键字,如果我想引用一个全局变量或函数a,我只要直接在源文件中包含#include<xxx.h> (xxx.h包含了a的声明)不就可以了么,为什么还要用extern呢??这个问题一直也是似是而非的困扰着我许多年了,今天上网狠狠查了一下总算小有所获了:
头文件
首先说下头文件,其实头文件对计算机而言没什么作用,她只是在预编译时在#include的地方展开一下,没别的意义了,其实头文件主要是给别人看的。
我做过一个实验,将头文件的后缀改成xxx.txt,然后在引用该头文件的地方用
#include"xxx.txt"
编译,链接都很顺利的过去了,由此可知,头文件仅仅为阅读代码作用,没其他的作用了!
不管是C还是C++,你把你的函数,变量或者结构体,类啥的放在你的.c或者.cpp文件里。然后编译成lib,dll,obj,.o等等,然后别人用的时候最基本的gcc hisfile.cpp yourfile.o|obj|dll|lib 等等。
但对于我们程序员而言,他们怎么知道你的lib,dll...里面到底有什么东西?要看你的头文件。你的头文件就是对用户的说明。函数,参数,各种各样的接口的说明。
那既然是说明,那么头文件里面放的自然就是关于函数,变量,类的“声明”了。记着,是“声明”,不是“定义”。
那么,我假设大家知道声明和定义的区别。所以,最好不要傻嘻嘻的在头文件里定义什么东西。比如全局变量:

#ifndef _XX_头文件.H
#define _XX_头文件.H
int A;
#endif

那么,很糟糕的是,这里的int A是个全局变量的定义,所以如果这个头文件被多次引用的话,你的A会被重复定义
显然语法上错了。只不过有了这个#ifndef的条件编译,所以能保证你的头文件只被引用一次,不过也许还是会岔子,但若多个c文件包含这个头文件时还是会出错的,因为宏名有效范围仅限于本c源文件,所以在这多个c文件编译时是不会出错的,但在链接时就会报错,说你多处定义了同一个变量,
Linking...
incl2.obj : error LNK2005: "int glb" (?glb@@3HA) already defined in incl1.obj
Debug/incl.exe : fatal error LNK1169: one or more multiply defined symbols found
注意!!!
extern
这个关键字真的比较可恶,在声明的时候,这个extern居然可以被省略,所以会让你搞不清楚到底是声明还是定义,下面分变量和函数两类来说:
(1)变量
尤其是对于变量来说。
extern int a;//声明一个全局变量a
int a; //定义一个全局变量a
extern int a =0 ;//定义一个全局变量a 并给初值。
int a =0;//定义一个全局变量a,并给初值,
第四个 等于 第 三个,都是定义一个可以被外部使用的全局变量,并给初值。
糊涂了吧,他们看上去可真像。但是定义只能出现在一处。也就是说,不管是int a;还是extern int a=0;还是int a=0;都只能出现一次,而那个extern int a可以出现很多次。
当你要引用一个全局变量的时候,你就要声明,extern int a;这时候extern不能省略,因为省略了,就变成int a;这是一个定义,不是声明。
(2)函数
函数,函数,对于函数也一样,也是定义和声明,定义的时候用extern,说明这个函数是可以被外部引用的,声明的时候用extern说明这是一个声明。 但由于函数的定义和声明是有区别的,定义函数要有函数体,声明函数没有函数体,所以函数定义和声明时都可以将extern省略掉,反正其他文件也是知道这个函数是在其他地方定义的,所以不加extern也行。两者如此不同,所以省略了extern也不会有问题。
比如:
int fun(void)
{
return 0;
}
很好,我们定义了一个全局函数
int fun(void);
我们对它做了个声明,然后后面就可以用了
加不加extern都一样
我们也可以把对fun的声明 放在一个头文件里,最后变成这样
int fun(void);//函数声明,所以省略了extern,完整些是extern int fun(void);
int fun(void)
{
return 0;
}//一个完整的全局函数定义,因为有函数体,extern同样被省略了。
然后,一个客户,一个要使用你的fun的客户,把这个头文件包含进去,ok,一个全局的声明。没有问题。
但是,对应的,如果是这个客户要使用全局变量,那么要extern 某某变量;不然就成了定义了。
总结下:
对变量而言,如果你想在本源文件中使用另一个源文件的变量,就需要在使用前用extern声明该变量,或者在头文件中用extern声明该变量;
对函数而言,如果你想在本源文件中使用另一个源文件的函数,就需要在使用前用声明该变量,声明函数加不加extern都没关系,所以在头文件中函数可以不用加extern。
C程序采用模块化的编程思想,需合理地将一个很大的软件划分为一系列功能独立的部分合作完成系统的需求,在模块的划分上主要依据功能。模块由头文件和实现文件组成,对头文件和实现文件的正确使用方法是:
规则1 头文件(.h)中是对于该模块接口的声明,接口包括该模块提供给其它模块调用的外部函数及外部全局变量,对这些变量和函数都需在.h中文件中冠以extern关键字声明;
规则2 模块内的函数和全局变量需在.c文件开头冠以static关键字声明;
规则3 永远不要在.h文件中定义变量;
许多程序员对定义变量和声明变量混淆不清,定义变量和声明变量的区别在于定义会产生内存分配的操作,是汇编阶段的概念;而声明则只是告诉包含该声明的模块在连接阶段从其它模块寻找外部函数和变量。如:
int a = 5;
#include “module1.h”
#include “module1.h”
#include “module1.h”
以上程序的结果是在模块1、2、3中都定义了整型变量a,a在不同的模块中对应不同的地址单元,这明显不符合编写者的本意。正确的做法是:
extern int a;
#include “module1.h”
int a = 5;
#include “module1.h”
#include “module1.h”  
这样如果模块1、2、3操作a的话,对应的是同一片内存单元。

规则4 如果要用其它模块定义的变量和函数,直接包含其头文件即可。
许多程序员喜欢这样做,当他们要访问其它模块定义的变量时,他们在本模块文件开头添加这样的语句:
extern int externVar; 
抛弃这种做法吧,只要头文件按规则1完成,某模块要访问其它模块中定义的全局变量时,只要包含该模块的头文件即可。
共享变量声明
就像在函数间共享变量的方式一样,变量可以在文件中共享。为了共享函数,要把函数的定义放在一个源文件中,然后在需要调用此函数的其他文件中放置声明。共享变量的方法和此方式非常类似。
在此之前,不需要区别变量的声明和它的定义。为了声明变量i,写成如下形式:
int i;
这样不仅声明i是int型的变量,而且也对i进行了定义,从而使编译器为i留出了空间。为了声明没有定义的变量i,需要在变量声明的开始处放置关键字extern:
extern int i;
extern提示编译器变量i是在程序中的其他位置定义的(大多数可能是在不同的源文件中),因此不需要为i分配空间。
顺便说一句,extern可以用于所有类型的变量。在数组的声明中使用extern时,可以忽略数组的长度:
extern int a[];
因为此刻编译器不用为数组a分配空间,所以也就不需要知道数组a的长度了。
为了在几个源文件中共享变量i,首先把变量i的定义放置在一个文件中:
int i;
如果需要对变量i初始化,那么可以在这里放初始值。在编译这个文件时,编译器将会为变量i分配内存空间,而其他文件将包含变量i的声明:
extern int i;
通过在每个文件中声明变量i,使得在这些文件中可以访问/或修改变量i。然而,由于关键字extern,使得编译器不会在每次编译其中某个文件时为变量i分配额外的内存空间。
当在文件中共享变量时,会面临和共享函数时相似的挑战:确保变量的所有声明和变量的定义一致。
为了避免矛盾,通常把共享变量的声明放置在头文件中。需要访问特殊变量的源文件可以稍后包含适当的头文件。此外,含有变量定义的源文件包含每一个含有变量声明的头文件,这样使编译器可以检查两者是否匹配。
如果工程很大,头文件很多,而有几个头文件又是经常要用的,那么
1。把这些头文件全部写到一个头文件里面去,比如写到preh.h
2。写一个preh.c,里面只一句话:#include "preh.h"
3。对于preh.c,在project setting里面设置creat precompiled headers,对于其他
c文件,设置use precompiled header file
分享到:
评论

相关推荐

    c语言中头文件的-函数-全局变量

    C语言中头文件的函数和全局变量 C语言中头文件的主要作用是提供一个存放重复使用代码的空间,例如函数声明、变量声明、常数定义、宏的定义等等。头文件的内容可以被多个源文件引用,以便实现代码的重用和共享。 ...

    MFC中定义全局变量和全局函数的方法

    ### MFC中定义全局变量和全局函数的方法 #### 引言 在Microsoft Foundation Classes (MFC)框架下进行软件开发时,经常会遇到需要在不同类之间共享数据或功能的情况。由于MFC项目的复杂性,简单地定义全局变量或函数...

    C语言面试题大汇总之华为面试题:1、局部变量能否和全局变量重名;2、如何引用一个已经定义过的全局变量;3、全局变量可不可以定义在可被多个.C文件包含的头文件中 为什么;4、语句for( ;1 ;)有什么问题 它是什么意思……

    本文总结了C语言面试题大汇总之华为面试题,涵盖了局部变量、全局变量、extern关键字、for循环、while循环、静态变量、静态函数、内存分配等知识点。 一、局部变量和全局变量 局部变量可以与全局变量同名,在函数...

    C/C++语言中全局变量重复定义问题的解决方法

    宏定义、结构体定义、函数声明以及全局变量定义放到一个head.h头文件中 函数的定义放到head.cpp中 main函数放到main.cpp中 然而却报错了,提示xxx变量在*.obj文件中已定义 问题出现的原因 为什么会出现这种...

    c语言中头文件的建立与使用-函数、全局变量、全局数组

    头文件本质上是一个包含了函数声明、变量声明、常量定义、宏定义等的文本文件。通过使用头文件,可以在多个源文件(`.c`文件)之间共享这些定义。创建头文件的方法非常简单,只需要使用文本编辑器编写相应的代码,并以...

    C语言在头文件中定义const变量详解

    C语言在头文件中定义const变量详解 在头文件中定义const不会有多变量的警告或错误,如果该头文件被大量包含会造成rom空间的浪费。 通过查看*.i文件的展开呢,可以发现每个.i文件都会有相应的变量展开。 查看*.map...

    QT 使用全局变量的方法 - 郭小郭的专栏 - CSDN博客1

    首先,在一个头文件(例如`aaa.h`)中声明全局变量: ```cpp #ifndef AAA_H #define AAA_H int var_name; static bool fun() { dosth } #endif // AAA_H ``` 然后,在主程序文件(例如`main.cpp`)中引用这个...

    在MFC下如何定义全局变量和全局函数.doc

    - **线程安全**:在多线程环境中使用全局变量时需特别小心,因为多个线程可能同时访问同一个全局变量,从而引发数据竞争等问题。 #### 七、总结 通过本文的学习,我们了解了如何在MFC项目中定义和使用全局变量及...

    在MFC下如何定义全局变量和全局函数

    ### 在MFC下定义全局变量和全局函数的方法 在MFC环境下开发的应用程序通常由多个文件组成,这使得全局变量和全局函数的定义变得相对复杂。为了能够在整个项目范围内访问某些变量或函数,开发者需要采取特定的方法来...

    局部变量和全局变量总汇

    3. **全局变量可不可以定义在可被多个.C文件包含的头文件中?** - **答案**:可以,但是需要注意的是,虽然可以在不同的`.c`文件中声明同名的全局变量,但必须确保只有一个`.c`文件中对此变量进行初始化,否则会...

    头文件不宜定义变量的原因全面解析

    然而,头文件不宜用来定义变量,原因在于这样做可能导致重复定义的问题,从而引起编译错误。以下是对此问题的详细解析: 首先,头文件的主要目的是为了提供接口信息,而不是实现细节。当头文件中定义了变量,每个...

    全局 变量 extern

    不能在头文件.h里面定义全局变量,如果头文件中可以定义全局变量,那么每个包含该头文件的文件里都会有该全局变量的定义.因为C语言的include是直接将文件嵌入到include这个地方的. ...

    在C/C++项目中使用全局变量的方法

    然而,不当的使用全局变量可能会引入一系列问题,如命名冲突、代码可维护性降低等。因此,了解如何正确地在项目中管理和使用全局变量至关重要。 #### 方法一:通过`.cpp`文件定义和引用全局变量 **定义**:首先在...

    C/C++ 跨文件共享全局变量Demo

    请注意,跨文件共享全局变量虽然方便,但也存在一些潜在问题,如: - **作用域和生命周期**:全局变量在整个程序的生命周期内都存在,可能导致内存泄漏和意外修改。 - **依赖性**:过度依赖全局变量会使代码难以...

    STM32无阻塞控制LED,可以设置LED占空比和闪烁次数,采用TIM精确定时,采用宏定义定义数字,全局变量在头文件中声明。

    STM32无阻塞控制LED,可以设置LED占空比和闪烁次数,采用TIM精确定时,采用宏定义定义数字,全局变量在头文件中声明,采用静态全局变量避免变量暴露; 2. 使用说明: 通过修改宏定义可以修改开关时间; 通过查看...

    防止变量重复定义、头文件重复包含、嵌套包含

    在C/C++程序中,头文件通常包含了函数声明、类型定义等信息。如果一个头文件被多个源文件包含,或者在一个源文件中被多次包含,则会导致不必要的重复和潜在的编译错误。 **解决方法:** 为了避免重复包含头文件,...

    C++的头文件问题

    * 不提倡使用全局变量,尽量不要在头文件中出现象 extern int value 这类声明。 4. 定义文件的结构 定义文件是 C++/C 程序中的一种重要组成部分,它们通常以“.cpp”为后缀,用于保存程序的实现(implementation)...

Global site tag (gtag.js) - Google Analytics