c++多个文件中如何共用一个全局变量

例子:html

头文件:state.h   源文件:state.cpp       程序员

 其它源文件:t1.cpp  t2.cpp  t3.cpp, 这些源文件都包含头文件state.h。编程

须要定义一个全局变量供这些源文件中使用:方法以下数组

一、在 state.h声明全局变量: extern inta;模块化

二、在state.cpp中定义该全局变量:int a =10;函数

这样其它源文件就可使用该变量啦post

 

 

这里须要的是“声明”,不是“定义”!根据C++标准的规定,一个变量声明必须同时知足两个条件,不然就是定义:  
 (1)声明必须使用extern关键字;(2)不能给变量赋初值    
  extern  int  a;  //声明 
优化


 int  a;   //定义url

 int  a  =  0; //定义spa

 extern  int  a  =0;   //定义

 

 

     头文件中应使用extern关键字声明全局变量(不定义),若是这个变量有多个文件用到,能够新建一个cpp,在其中定义,把这个cpp加入工程便可。头文件请不要定义任何变量,那是很是业余的行为……

    通常在头文件中申明,用extern,在cpp中定义。 若是在头文件中定义,若是这个头文件被多个cpp引用,会形成重复定义的连接错误。

    头文件只能申明全局变量(extern),不可定义(不推荐使用)    .cpp里,在最外层定义便可(int gi),直接引用

若是在.cpp里使用static定义,则该变量只在当前cpp文件中有效,在别的文件中无效
在.h里使用static定义,不会进行编译(.h文件不编译),只会在其每一个include的cpp文件中包含编译,至关于在.cpp里使用static定义。

转载:http://www.cnblogs.com/yyxt/p/3891712.html

1 基本解释:extern能够置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其余模块中寻找其定义。此外extern也可用来进行连接指定。

      也就是说extern有两个做用,第一个,当它与"C"一块儿连用时,如: extern "C" void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun这个名字变得面目全非,多是fun@aBc_int_int#%$也多是别的,这要看编译器的"脾气"了(不一样的编译器采用的方法不同),为何这么作呢,由于C++支持函数的重载啊,在这里不去过多的论述这个问题,若是你有兴趣能够去网上搜索,相信你能够获得满意的解释!(C++ 和 C 采用的名称修饰规则不一样)
    第二,当extern不与"C"在一块儿修饰变量或函数时,如在头文件中: extern int g_Int; 它的做用就是声明函数或全局变量的做用范围的关键字,其声明的函数和变量能够在本模块活其余模块中使用,记住它是一个声明不是定义!也就是说B模块(编译单元)要是引用模块(编译单元)A中定义的全局变量或函数时,它只要包含A模块的头文件便可,在编译阶段,模块B虽然找不到该函数或变量,但它不会报错,它会在链接时从模块A生成的目标代码中找到此函数。

2 问题:extern 变量
  在一个源文件里定义了一个数组:char a[6];
  在另一个文件里用下列语句进行了声明:extern char *a;
  请问,这样能够吗? 
  答案与分析:
  1)、不能够,程序运行时会告诉你非法访问。缘由在于,指向类型T的指针并不等价于类型T的数组。extern char *a声明的是一个指针变量而不是字符数组,所以与实际的定义不一样,从而形成运行时非法访问。应该将声明改成extern char a[ ]。
  2)、例子分析以下,若是a[] = "abcd",则外部变量a=0x61626364 (abcd的ASCII码值),*a显然没有意义
  显然a指向的空间(0x61626364)没有意义,易出现非法内存访问。
  3)、这提示咱们,在使用extern时候要严格对应声明时的格式,在实际编程中,这样的错误家常便饭。
  4)、extern用在变量声明中经常有这样一个做用,你在*.c文件中声明了一个全局的变量,这个全局的变量若是要被引用,就放在*.h中并用extern来声明。

3 问题:单方面修改extern 函数原型
  当函数提供方单方面修改函数原型时,若是使用方不知情继续沿用原来的extern申明,这样编译时编译器不会报错。可是在运行过程当中,由于少了或者多了输入参数,每每会照成系统错误,这种状况应该如何解决?
  答案与分析:
  目前业界针对这种状况的处理没有一个很完美的方案,一般的作法是提供方在本身的xxx_pub.h中提供对外部接口的声明(extern),而后调用方include该头文件,从而省去extern这一步。以免这种错误。
  宝剑有双锋,对extern的应用,不一样的场合应该选择不一样的作法。

4 问题:extern “C”
  在C++环境下使用C函数的时候,经常会出现编译器没法找到obj模块中的C函数定义,从而致使连接失败的状况,应该如何解决这种状况呢?

  答案与分析:
  C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,所以会形成连接时找不到对应函数的状况,此时C函数就须要用extern “C”进行连接指定,这告诉编译器,请保持个人名称,不要给我生成用于连接的中间函数名。
  下面是一个标准的写法:

复制代码
//在.h文件的头上
#ifdef __cplusplus
#if __cplusplus
extern "C"{
 #endif
 #endif /* __cplusplus */ 
 …
 …
 //.h文件结束的地方
 #ifdef __cplusplus
 #if __cplusplus
}
#endif
#endif /* __cplusplus */ 
复制代码

 

5 问题:extern 函数声明
  经常见extern放在函数的前面成为函数声明的一部分,那么,C语言的关键字extern在函数的声明中起什么做用?
  答案与分析:
  若是函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它做用。即下述两个函数声明没有明显的区别:

extern int f(); 

int f();


  固然,这样的用处仍是有的,就是在程序中取代include “*.h”来声明函数,在一些复杂的项目中,我比较习惯在全部的函数声明前添加extern修饰。关于这样作的缘由和利弊可见下面的这个例子:“用extern修饰的全局变量”

    (1) 在test1.h中有下列声明:

    #ifndef TEST1H
    #define TEST1H
    extern char g_str[]; // 声明全局变量g_str
    void fun1();
    #endif

    (2) 在test1.cpp中

    #include "test1.h"
        char g_str[] = "123456"; // 定义全局变量g_str
        void fun1() { cout << g_str << endl; }

    (3) 以上是test1模块, 它的编译和链接均可以经过,若是咱们还有test2模块也想使用g_str,只须要在原文件中引用就能够了

    #include "test1.h"

     void fun2()    { cout << g_str << endl;    }

    以上test1和test2能够同时编译链接经过,若是你感兴趣的话能够用ultraEdit打开test1.obj,你能够在里面找到"123456"这个字符串,可是你却不能在test2.obj里面找到,这是由于g_str是整个工程的全局变量,在内存中只存在一份,test2.obj这个编译单元不须要再有一份了,否则会在链接时报告重复定义这个错误!

注意:若是使用到sizeof,声明数组须要指定大小 extern char g_str[7]; 由于test2模块中只是声明了一个数组,但具体多大,并不知道。若没有在.h文件中声明数组大小,会报“非法的sizeof操做数”的错误。

  (4) 有些人喜欢把全局变量的声明和定义放在一块儿,这样能够防止忘记了定义,如把上面test1.h改成
   

extern char g_str[] = "123456"; // 这个时候至关于没有extern

    而后把test1.cpp中的g_str的定义去掉,这个时候再编译链接test1和test2两个模块时,会报链接错误,这是由于你把全局变量g_str的定义放在了头文件以后,test1.cpp这个模块包含了test1.h因此定义了一次g_str,而test2.cpp也包含了test1.h因此再一次定义了g_str,这个时候链接器在链接test1和test2时发现两个g_str。若是你非要把g_str的定义放在test1.h中的话,那么就把test2的代码中#include "test1.h"去掉 换成:

extern char g_str[];  // 没有include “test1.h”
void fun2()   {  cout << g_str << endl;   }


   这个时候编译器就知道g_str是引自于外部的一个编译模块了,不会在本模块中再重复定义一个出来,可是我想说这样作很是糟糕,由于你因为没法在test2.cpp中使用#include "test1.h",那么test1.h中声明的其余函数你也没法使用了,除非也用都用extern修饰,这样的话你光声明的函数就要一大串,并且头文件的做用就是要给外部提供接口使用的,因此 请记住, 只在头文件中作声明,真理老是这么简单。

6. extern 和 static

 (1) extern 代表该变量在别的地方已经定义过了,在这里要使用那个变量.
 (2) static 表示静态的变量,分配内存的时候, 存储在静态区,不存储在栈上面.

    static 做用范围是内部链接的关系, 和extern有点相反.它和对象自己是分开存储的,extern也是分开存储的,可是extern能够被其余的对象用extern 引用,而static 不能够,只容许对象自己用它. 具体差异首先,static与extern是一对“水火不容”的家伙,也就是说extern和static不能同时修饰一个变量;其次,static修饰的全局变量声明与定义同时进行,也就是说当你在头文件中使用static声明了全局变量(类外部)后(若是在头文件的class内部声明static变量,那么其定义式一般位于实现(.cpp)文件中,例外的,只有const int类型能够in class 初值设定),它也同时被定义了;最后,static修饰全局变量的做用域只能是自己的编译单元(内部连接,参见 存储持续性、做用域和连接性),也就是说它的“全局”只对本编译单元有效,其余编译单元则看不到它,如:
    (1) test1.h:

#ifndef TEST1H
#define TEST1H
static char g_str[] = "123456"; 
void fun1();
#endif

    (2) test1.cpp:

#include "test1.h"
void fun1()  {   cout << g_str << endl;  }

    (3) test2.cpp

#include "test1.h"
void fun2()  {   cout << g_str << endl;  }

    以上两个编译单元能够链接成功, 当你打开test1.obj时,你能够在它里面找到字符串"123456",同时你也能够在test2.obj中找到它们,它们之因此能够链接成功而没有报重复定义的错误是由于虽然它们有相同的内容,可是存储的物理地址并不同,就像是两个不一样变量赋了相同的值同样,而这两个变量分别做用于它们各自的编译单元。 也许你比较较真,本身偷偷的跟踪调试上面的代码,结果你发现两个编译单元(test1,test2)的g_str的内存地址相同,因而你下结论static修饰的变量也能够做用于其余模块,可是我要告诉你,那是你的编译器在欺骗你,大多数编译器都对代码都有优化功能,以达到生成的目标程序更节省内存,执行效率更高,当编译器在链接各个编译单元的时候,它会把相同内容的内存只拷贝一份,好比上面的"123456", 位于两个编译单元中的变量都是一样的内容,那么在链接的时候它在内存中就只会存在一份了,若是你把上面的代码改为下面的样子,你立刻就能够拆穿编译器的谎话:
    (1) test1.cpp:

#include "test1.h"
void fun1()
{
   g_str[0] = ''a'';
   cout << g_str << endl;
}

    (2) test2.cpp

#include "test1.h"
void fun2()  {  cout << g_str << endl;  }

    (3) 

void main()     {
        fun1(); // a23456
        fun2(); // 123456
    }

    这个时候你在跟踪代码时,就会发现两个编译单元中的g_str地址并不相同,由于你在一处修改了它,因此编译器被强行的恢复内存的原貌,在内存中存在了两份拷贝给两个模块中的变量使用。正是由于static有以上的特性,因此通常定义static全局变量时,都把它放在原文件中而不是头文件,这样就不会给其余模块形成没必要要的信息污染,一样记住这个原则吧!

7. extern 和const

   C++中const修饰的全局常量据有跟static相同的特性,即它们只能做用于本编译模块中,可是const能够与extern连用来声明该常量能够做用于其余编译模块中, 如extern const char g_str[];
    而后在原文件中别忘了定义:     const char g_str[] = "123456"; 

    因此当const单独使用时它就与static相同,而当与extern一块儿合做的时候,它的特性就跟extern的同样了!因此对const我没有什么能够过多的描述,我只是想提醒你,const char* g_str = "123456" 与 const char g_str[] ="123465"是不一样的, 前面那个const 修饰的是char *而不是g_str,它的g_str并非常量,它被看作是一个定义了的全局变量(能够被其余编译单元使用), 因此若是你像让char*g_str遵照const的全局常量的规则,最好这么定义const char* const g_str="123456".

【转】http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777431.html

 

/*************************************************************************/

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”
以上程序的结果是在模块一、二、3中都定义了整型变量a,a在不一样的模块中对应不一样的地址单元,这明显不符合编写者的本意。正确的作法是:
extern int a;
#include “module1.h”
int a = 5;
#include “module1.h”
#include “module1.h”  
这样若是模块一、二、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.h2。写一个preh.c,里面只一句话:#include "preh.h"3。对于preh.c,在project setting里面设置creat precompiled headers,对于其余c文件,设置use precompiled header file

相关文章
相关标签/搜索