extern关键字的知情和效果与利益深刻,的程序的文件结构

Posted by

     
因项目必要,要求对C++的程序的文本结构具备调整:由此在网络找了上面包车型客车小说供就学和参照。希望对刚入门的C++朋友能提供部分扶植。
转载:

变量的注解和定义以及extern的用法

 extern关键字的知晓和效果与利益深切  

程序是由什么组成的? 学习到今天,大家起码有三个答案:

                                        

extern是贰个主要字,它告诉编写翻译器存在着三个变量恐怕四个函数,假诺在现阶段编译语句的前方中从未找到呼应的变量恐怕函数,

第1,程序由代码语句组成。正是一行行的代码,组成了一个安然无事的次第。

变量的宣示不一样于变量的定义,这点往往轻便令人歪曲。

也会在当下文件的前边可能别的文件中定义

第2,程序由函数组成。三个个函数之间的相互调用,最终营造出一个整机的次序。

l        
变量的宣示是报告编写翻译器,该变量名称已经存在,编写翻译器认知那些名字,不会唤起编写翻译错误。

引文一、(主假设实战中的种种境况)

前几天我们又有七个新的回应:“程序由文件组成”。

l        
对变量实行定义之后,编译器就可以给变量分配空间,链接时,链接器可以找到它们的地点。

主导解释:extern能够停放变量或然函数前,以标示变量只怕函数的概念在其他文件中,提醒编译器碰着此变量和函数时在其余模块中搜索其定义。别的extern也可用来进展链接钦赐。

程序为何必要动用多少个文本?

在程序代码组织进程中,大家频仍把变量的宣示放在头文件中,而把变量的概念放在源文件中,如上边包车型地铁例子所示(该例子在VC6.0中编写翻译、链接通过):

      也便是说extern有多少个成效,第多个,当它与”C”一齐连用时,如: extern
“C” void fun(int a, int
b);则告诉编写翻译器在编写翻译fun那么些函数名时按着C的平整去翻译相应的函数名而不是C++的,C++的条条框框在翻译这一个函数名时会把fun这一个名字变得改头换面,或者是fun@aBc_int_int#%$也只怕是其他,那要看编写翻译器的”性格”了(差异的编写翻译器选拔的点子不一致等),为何如此做吧,因为C++支持函数的重载啊,在那边不去过多的阐发那几个标题,假若您有乐趣可以去网络搜寻,相信你能够拿到满足的表达!
    第二,当extern不与”C”在同步修饰变量或函数时,如在头文件中: extern
int
g_Int; 它的作用正是声称函数或全局变量的成效范围的器重字,其宣称的函数和变量能够在本模块活其余模块中央银行使,记住它是八个宣称不是概念!约等于说B模块(编写翻译单元)倘使援用模块(编写翻译单元)A中定义的全局变量或函数时,它若是包罗A模块的头文件就可以,在编写翻译阶段,模块B就算找不到该函数或变量,但它不会报错,它会在连年时从模块A生成的指标代码中找到此函数。

一个小的次序,能够只写三个源文件,但先后稍微一大,就供给将里面差别的逻辑达成放到不一样的源文件.对于急需多少人合伙付出的软件,自然更须求几个源文件。

file1.h

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中提供对表面接口的扬言,然后调用方include该头文件,从而省去extern这一步。以制止这种漏洞非常多。
  宝剑有双锋,对extern的应用,差别的场子应该选拔不一样的做法。

14.1 源文件和头文件

 

和别的一些语言差别,C,C++的代码文件有“头文件”和“代码文件”之分。二者合起来大家称为单元(Unit)文件。

 

增加名称为 .c 或 .cpp
的文本,重要用于完毕程序的各类成效,我们誉为代码文件。

庞大名叫 .h
的公文,称为头文件。在头文件里主要写一些函数、数据(包罗数据类型的概念)、等的扬言,那样能够在多少个.c或.cpp文件内共享这一个函数、数据。第12章大家提过到头文件的作用。说它能够起到函数“著名影片夹”的效应。 

大都数时候,源文件和头文件是对应出现的,譬如有叁个A.cpp 的源文件,就能够有贰个 A.h
的头文件。这种景色在大家写应用程序时,更是广大。所以C++
Builder对此进行了无中生有。比如,它扶助在同名源文件和头文件之间通过热键来回切换。在CB6.0里,编辑器展开对应的源文件和头文件时,将显得为同样页下的八个子页。

大家来实在出手看看源文件与头文件在CB里的附和关系。 

运行 C++ Builder 6或5。

这一回我们供给八个空白的Windows工程。很有望,在你展开CB时,它就机关为你张开了贰个工程。为了不不可靠,大家依然亲自行建造三个。CB6请使用主菜单:File | New | Application;而CB5则采取:File | New Application 新建八个Windows 空白工程
要是在这进度中CB出现是或不是存盘的打听,请回复不存盘。 

找到“代码窗口”。倘诺您看到的是三个叫”Form1″的表单,请按F12,“代码窗口”将跑到眼下。它的标题应该是暗中认可的”Unit1.cpp”。就是当前代码文件的文本名。如下图: 

图片 1

对此CB6,还可以够看看在该窗口的底层有如此三个分页: 

图片 2

 

源文件:Unit1.cpp 和头文件:Unit1.h 并列着,大家可以一本万利地挑选。至于
“Diagram”,称为“图解”。那是二个给那几个源文件加配套表明,及表单上各控件的依赖关系的位置。假设是三个支出小组在展开共同开采,严峻地供给各类成员为每种单元文件写上“Diagram”,可以更加好地贯彻工程师之间的调换。

CB5未有这几个,可是下边的热键操作五个本子均一致的,供给我们记住。

按 Ctrl + F6
能够在源文件和头文件之间来回切换。请我们试试。这些差不离的操作就要大家以往的编制程序进程中高效用地行使。

 

// 文件名:file1.h

4 问题:extern “C”
  在C++碰到下使用C函数的时候,常常汇合世编写翻译器不可能找到obj模块中的C函数定义,从而致使链接退步的意况,应该如何消除这种意况吗?

14.2 怎么着成立多少个单元文件

 

近来大家在“Windows应用程序工程”中看出了头文件与源文件的同盟关系,在“调整台”的工程中,也同等存在。可是出于调整台常常只用来写一些细小程序,所今后往只需贰个源文件就能够。由于唯有三个源文件,所以也就不设有函数、数据在多个公文之间“分享”的需求,因此边头文件也就足以不提供。

 

那就是说,是还是不是唯有在程序非常的大,可能唯有在有不胜枚进士同期支付一个软件时,才需求几个源文件呢?

那就恍如你家里只有两本书:《红楼》和《Green童话》,是把它们位于同二个抽屉里呢?依然分开放到四个抽屉里?小编觉着后面一个是比较好的选项。因为我们常常希望家里看《Green童话》的人,最棒不要去看《红楼梦》。

先后也一直以来,最棒把差异的逻辑实现,放到不一致的源文件中。

 

上边大家做一个实例。例子的代码大家都已经学过。指标是贯彻叁个得以求总结值和平均值的先后。

基于大家前些天所学的图景,作者把那个工程中的代码分为多少个源代码:

以此:主程序。就是main()函数所在的代码。这几个源文件贯彻总的流程。小编将该公文取为
main.cpp。

其二:总计总和及计算平均值的代码。那么些源文件负担用户总括进程,也包蕴种种进程所需输入输出。该公文将被存盘为mainfunc.cpp。 意为机要功效。

其三: assifunc.cpp。表示帮忙功用函数所在代码。它只提供三个函数:将用户输入的大写或小写的假名’Y’或’N’ 确定保障调换为大写。那么些函数将main()主函数内,剖断用户是不是持续时用到。

 

新CB新建七个调节台程序(假让你还开着上个程序,先选File
| Close All关闭它)。CB会自动生成第三个文件,然而现在的名叫“Unit1.cpp”。

接下去是一项新职业,我们来增加五个人新的单元文件,即上边说的“其二”和“其三”。

CB6 :File | New | Unit;CB5:File | New Unit。

请进行两回以上操作,CB将为我们转换新的五个单元文件:Unit2.cpp和Unit3.cpp。大家能够再尝试 Ctrl + F6。(注意,第一个单元文件:Unit1.cpp
没有配套的.h文件,所以并非在该公文里品尝Ctrl + F6)。

接下来采纳File | Save All。全部存盘,最棒不要存在CB默许的目录下。记得按以下关系重命名:

Unit1.cpp 存盘为 main.cpp;

Unit2.cpp 存盘为 mainfunc.cpp;

Unit3.cpp 存盘为 assifunc.cpp;

关于总的工程,随你便,作者图方便,依然叫:Project1.bpr。

 

图片 3(今后大家率先次在一个工程中用到五个源文件。所以您得学会怎么飞快张开贰个工程中有些源文件——当然,以往那五个文件都早就开拓着,不过只要你有一点点事关闭CB,大家不愿意下回展开这么些工程时,你“找”不到第2和首个公文了——请点击CB工具栏上的这么些Logo:图片 4,将面世源文件列表对话框,如左图)

 

 

接下去讲在那七个公文中,大家独家写些什么?大大多代码大家都已经在前头学过,所以作者对代码的法力不作太多的分解。大家的关键是:多少个源文件之间的代码怎么样促成“调换”。

 

第四个公文:main.cpp 用来贯彻程序的主流程。

在 main.cpp 中的main()函数内,我们进入代码。

 

#include <iostream.h>

… …

int main(int argc, char* argv[])

{

   char ch;

   int count; //求总和或平均值时,供给输入的实际业绩个数

 

   do

   {

      cout << “1)求总和” << endl;

      cout << “2)求平均” << endl;

    

      cout << “请选择(1 或 2)”;

      cin >> ch;

     

      //输入有误,重输:

      if(ch != ‘1’ && ch != ‘2’)

      {

         cout << “输入有误,请重新输入!” << endl;

         continue;

      }

     

      cout << “请输入个数:”;

      cin >> count;

     

      //根据用户的接纳,调用分裂函数:

      switch(ch)

      {

         case ‘1’ :

            CalcTotal(count); //须求调用的函数之一

            break;

         case ‘2’ :

            CalcAverage(count); //必要调用的函数之一

            break;

      }

        

      //是不是持续:

      cout << “是不是继续?(y/n)”;

      cin >> ch;

     

      //确定保障转变为大写:

      ch = ToUpper(ch); //必要调用的函数之一

   }

   while(ch == ‘Y’);

  

   return 0;

}

 

代码中,葡萄紫部分的笺注申明,主函数main()须求调用到八个自定义函数。但近年来我们贰个也绝非定义。和未来把富有的函数定义在同贰个代码文件中差别,今日我们供给把它们分别到不一致的代码文件。

 

其次个文本:mainfunc.cpp 存放和计量有关的八个经过(函数)。

先看:CalcTotal()和CalcAverage()。那五个函数大家就要mainfunc.cpp文件钦命义。你只怕又忘了“定义”那么些术语?呵,便是“完毕”,更白点,正是在mainfunc.cpp文件内“写”这三个函数。

 

下边是mainfunc.cpp的剧情。在我们输入以下代码时,mainfunc.cpp已经有了有些不可或缺的内容,上边包车型客车代码,除了“#include
..”一行在文书最首外,其它均在原始内容之后加上。

 

#include <iostream.h> //在文件最首行

… …

//—————————————————————————

//求总和的经过

//参数:n 用户需求输入的个数

void CalcTotal(int n)

{

   int num;

   int sum = 0;

  

   for(int i=0;i<n;i++)

   {

      cout << “请输入第” << i+1 <<“个整数:”;

      cin >> num;

     

      sum += num;

   }

  

   cout << “总和为:” << sum << endl;

}

//—————————————————————————

//求平均值的进程

//参数:n 用户须求输入的个数

void CalcAverage(int n)

{

   int num;

   int sum = 0;

   float ave;

   for(int i=0;i<n;i++)

   {

      cout << “请输入第” << i+1 <<“个整数:”;

      cin >> num;

  

      sum += num;

   }

   //注意不要除0出错:

   if( n >=0 )

   {

      ave = (float)sum / n;

      cout << “平均值:” << ave << endl;

   }

   else

   {

      cout << “个数为0,不能够求平均。” << endl;

   }

}

//—————————————————————————

 

其八个文本:assifunc.cpp 用以存放接济成效的函数,未来唯有一个。

于今还差多个函数:ToUpper()。这些函数用来将用户输入的有些小写字母转变为大写。当然,假如用户输入的不是小写字母,那就不要改换。和地点的多少个函数差异,它供给重临值。

我们把ToUpper()函数单独放在assifunc.cpp里。同样,上面包车型大巴代码加在该公文中本来的代码之后。不过本文件不需求include
<iostream.h> ,因为未有动用 cin,cout等。

 

//小写字母调换为题写

//参数: c 待调换的字符

//重临值: 调换后的字符,借使原字符不是小写字母,则为原字符

char ToUpper(char c)

{

   int ca = ‘A’ – ‘a’; //大写字母和小写字母之间差距有一点?

   if(c >= ‘a’ && c <= ‘z’)

      c += ca;
 

   return c;

}

 

迄今,全体自定义函数都已变成定义(达成),而八个公文的根本内容也以明确。让大家看看暗暗表示图:

 

图片 5

 

main.cpp中的main()函数调用了多少个函数。回想大家上学过的“如何调用函数”的知识,当前代码在调用三个函数时,必须能“看到”这一个函数。纵然CalcTotal()、CalcAverage()、ToUpper()四个函数所在文件都在同等工程里,然则在main.cpp里的代码,依然看不到它们。想一想大家原先说的“请修理工科”的比如。未来意况是:在您所住的小区,以至纵然同一楼道里,就有二个电视机械修理理工科,担心痛你们互不认知,所以当你电视机坏了,想“调用”四个修理工科作时间,你照旧找不到修理工科。哎!若是有它的名片就好了。

让我们试试看,按Ctrl + F9,编辑该工程。出错!

图片 6

刚好是多少个错。分别报告大家调用了五个未有概念的函数(Call to undefined
function …)。

 

(倘若你出现的是一批错,那有十分大恐怕是你从未在前四个文件内最首行写:

“#include <iostream.h>”

抑或是您有个别代码输入有误。)

 

何以清除那八个错?三种方式。

首先种办法就是先前笔者们在讲“怎么样调用函数”的时候所说的,直接在调用直接评释要调用的函数。这里写出代码,算做是三遍复习,然后大家将讲该措施不佳之处。

 

在 main.cpp 的 main()函数以前加入如下三行函数评释:

 

void CalcTotal(int n);

void CalcAverage(int n);

char ToUpper(char c);

 

int main(int argc, char* argv[])

{

   … …

}

 

(上例中,即便你能够将三行函数注脚写在 main()函数体内,但不建议如此做)。

 

假若您全数输入正确的话,未来按Ctrl + F9 或 F9将得以做到编写翻译或运营。

对于前天以此工程,这种办法确实也不可能批评它有什么不利之处。问题在于,假如大家还应该有其他文件中代码须要调用到那四个函数,大家就只好在别的文件中也逐一写上这三行表明。所以另一种办法是:把源文件中需求对外“分享”的函数申明统一写到某块头文件,然后凡是要求动用的任何文件,直接动用“#include”语句来含有该头文件,从而得到这几个函数证明。

 

// 该文书档案用来测量试验extern的用法

  答案与剖析:
  C++语言在编写翻译的时候为了缓和函数的多态问题,会将函数名和参数联合起来生成三个中档的函数名称,而C语言则不会,由此会招致链接时找不到相应函数的情景,此时C函数就要求用extern
“C”举行链接内定,那告诉编写翻译器,请保持自身的名目,不要给自家生成用于链接的中级函数名。
  上面是贰个专门的工作的写法:
//在.h文件的头上
#ifdef __cplusplus
#if __cplusplus
extern “C”{
 #endif
 #endif /* __cplusplus */ 
 …
 …
 //.h文件截至的地点
 #ifdef __cplusplus
 #if __cplusplus
}
#endif
#endif /* __cplusplus */ 

14.3 如何写头文件

 

在CB中,假如您通过上小节的章程新建个单元文件,那么CB将电动同不常间生成源文件和头文件。其实在CB里,源文件和头文件合称为单元文件,它们有同等的文本名,而扩展名一者为.cpp,另一为.h。

 

// extern代表外界声美素佳儿个变量

5 问题:extern 函数声称
  平时见extern放在函数的先头成为函数证明的一部分,那么,C语言的根本字extern在函数的声明中起什么功用?
  答案与分析:
  假设函数的证明中蕴涵关键字extern,仅仅是示意这一个函数大概在其他源文件里定义,未有其它成效。即下述八个函数证明未有显明的差距:
extern int f(); 和int f();
  当然,这样的用处依旧某个,正是在先后中取代include
“*.h”来声称函数,在局地参差不齐的品种中,小编比较习贯在装有的函数注明前加多extern修饰。关于那样做的来由和利弊可知下边包车型地铁这些事例:“用extern修饰的全局变量”

14.3.1 在头文件内投入函数注脚

 

头文件:mainfunc.h

CalcTotal()和CalcAverage()函数定义在
mainfunc.cpp文件里,所以它们的扬言最棒写在相应的头文件mainfunc.h内。

上面大家就来看哪样在头文件mainfunc.h 内扩充函数表明。

一初步,头文件内有以下那个代码。别的,作者扩大了一行用于注解大家新加的代码应写在何地。

//—————————————————————————

#ifndef mainfuncH

#define mainfuncH

//—————————————————————————

/* !!!头文件中,大家新添的代码必须写在此地!!!  */

#endif

 

和源文件中新添代码加多在最终分化,头文件中新加代码
必须在#endif在此之前插入。所以本例中,加完函数申明的代码应如其下所示。(其余,CB总是在头文件的第二行留了一行空白行,小编不领会它那是假意依然无心。总来说之这里是我们写本文件总体注释的好地方。记住,头文件像名片,用于让外人看,很有要求写得详细点)

//—————————————————————————
   //重要操作函数

#ifndef mainfuncH

#define mainfuncH

//—————————————————————————

//总括总和:

void CalcTotal(int n);

//计算平均值:

void CalcAverage(int n);

//—————————————————————————

#endif

 

这正是“在头文件中扬言函数”的全部经过。上面是其它贰个头文件。

 

头文件:mainfunc.h

//—————————————————————————

//支持操作函数

#ifndef assifuncH

#define assifuncH

//—————————————————————————

//将字符调换来大写

char ToUpper(char c);

#endif

 

前天大家学的是怎么在头文件内注明函数,今后我们要求在头文件内申明变量,恐怕定义新的数据类型,它们都同样要求在上述的#endif在此以前参加。

 

// 声圣元个变量正是报告编写翻译器,那一个变量名已经存在

    (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”

14.3.2 最布满的预编写翻译语句

 

近日来注脚那三行话:

#ifndef mainfuncH

#define mainfuncH

 

#endif

 

中间的 #define mainfuncH
大家有一点点脸熟。在第五章《变量与常量》中,大家讲过用宏表示常数。语法为:

#define 宏名称 宏值

 

比如说,定义叁个∏值:

#define PAI 3.14159

 

此间大家学的是宏定义的另一种用法:仅仅定义贰个宏,不供给交给它的值,语法为:

 

#define 宏名称

 

比如:#define mainfuncH

 

概念了二个宏:mainfuncH。若是你无法清楚“宏”这么些词,不要紧就当把它表明成“旗号”。即编写翻译器通过该语句,做了三个标识,暗记名叫:mainfucH。

如此做的效力是什么呢?大家一而再看上下文。

 

#ifndef 中, if 是“如果”,n 是 no,即“还没有”,def是
define,即“定义”,那么:

#ifndef mainfuncH 意为:“倘若还尚未定义mainfuncH那么些宏”,那么……

那么未来做哪些吧?正是一向到 #endif之间的口舌。

 

总的再来看三遍:

 

mainfunc.h 中的首要内容:

 

#ifndef mainfuncH

#define mainfuncH

 

void CalcTotal(int n);

void CalcAverage(int n);

 

#endif

 

当编写翻译第2回编写翻译mainfunc.h文件时,宏 mainfuncH
还平昔不概念,因些,编写翻译器通过对 #define mainfuncH的编写翻译而产生了宏
mainfuncH。当编写翻译器第一遍编写翻译到 mainfunc.h文件时,宏mainfuncH
已经存在,所以该头文件被直接跳过,不会再一次管理该头文件中剧情,比如下边包车型地铁三个函数申明。

您恐怕会问五个问题:第一,为啥编写翻译器大概很多次编写翻译到同二个头文件?第二,为什么源文件,比方mainfunc.cpp就不必要采取#ifndef…
#endif?

那多个难题假若回答了里面贰个,另贰个也就自然消解。

 

这是由头文件天性所主宰的。头文件是用来被人家包罗(include)的。哪个人都能够钦赐要包括某三只文件,那样就只怕引致对该头文件的再次包蕴。

一经有头文件head.h。假若A文件包括了head.h,而B文件也隐含了head.h,那么编写翻译器不会在编写翻译A和编写翻译B时,都要对该头文件尝试编写翻译三回。

除此以外,头文件本人也能够包罗另三个头文件,这种场所下,各文件之间相互嵌套包蕴的情形就越来越多了。

 

源文件(.c或.cpp)就算能够,但貌似不被用来被别的文件包含,所以无需在源文件中加这么些话语。当然,若是须求,你也能够源文件中央银行使
#ifndef…#endif。

 

每生成多个头文件,包蕴在重命名它时,CB会为大家取好该头文件中,上述的宏名称,它取该头文件的全小写文件名,加上二个大写的‘H’字母,比方:
“mainfuncH”。请大家不用退换该宏的名称,避防出错。

 

除了 #ifndef … #endif 语句外,还会有它的相反逻辑的言辞: 

#ifdef … #endif
它是在固然有定义有些宏,那么,编译将持续其后的口舌。

 

除此以外就如有if 语句,还会有 if…else…语句同样,有 #ifdef …
#endif,也就还应该有这些讲话:

#ifdef

… …

#else

… …

#endif

 

可是这一个都和我们这里的头文件有关一点都不大,大家有时不讲。最终大家来分解四个名词“预编写翻译”。

编写翻译器在编写翻译代码时,至少须求四遍的编写翻译管理,个中第一遍,就是专程用来拍卖全体以
#开班的讲话,如上述的#ifndef…#endif、#define等等。这一回管理,大家称为预编译

 

// 然则尚未给它分配空间。也正是说,申明了叁个变量

     void fun2()    { cout << g_str << endl;    }
   
以上test1和test2能够同期编写翻译连接通过,假设你感兴趣的话能够用ultraEdit展开test1.obj,你能够在其间找到”123456″这几个字符串,可是你却无法在test2.obj里面找到,那是因为g_str是整套工程的全局变量,在内部存款和储蓄器中只存在一份,test2.obj那个编译单元无需再有一份了,不然会在一连时告诉再一次定义这些错误!
    (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[];
    void fun2()   {  cout << g_str << endl;   }
   那年编写翻译器就知道g_str是引自于表面的三个编写翻译模块了,不会在本模块中再重复定义一个出去,不过本身想说那样做老大不好,因为您由于不可能在test2.cpp中央银行使#include
“test1.h”,那么test1.h中宣示的别样函数你也无从接纳了,除非也用都用extern修饰,那样的话你光申明的函数将在第一次全国代表大会串,而且头文件的意义就是要给外界提供接口使用的,所以
请记住, 只在头文件中做评释,真理总是这么轻易

14.4 如何运用头文件

 

事实上我们平日在使用头文件。可是,在此以前大家直接在应用他人的头文件,前天是第一回选用我们自已的写的头件。

先前,大家大概各类例子,包蕴前天的例子中,都亟待在源文件的顶上部分写上一行:

#include <iostream.h>

或者:

#include <stdio.h>

 

iostream.h和stdio.h都以CB提必要我们的头文件。这个头文件随CB安装时,被保留在定位的文本夹内

后天的例证中,main.cpp 要求运用到在 mainfunc.h 和
assifunc.h。那是大家友好写的头文件,它们保存在大家自定的文书夹中

涵盖自已写的头文件,和包含CB提供的头文件并无多大分别。

请在 main.cpp 代码顶上部分,参与以下仿宋部分:

 

#include <iostream.h>

#include “mainfunc.h”

#include “assifunc.h”

//—————————————————————————

 

双面包车型客车细小分别是,包蕴CB提供的头文件时,用尖括号<>;而含有大家自已的头文件时,使用双引号“”。CB据此剖断什么找到内定的头文件。<>约等于告诉CB,这是您自已提供的头文件,到你安装时的头文件目录下找去呢,而“”则是报告CB,是那本人自已写的头文件,请首先到本人日前工程所在目录下搜寻,要是找不到,再到别的只怕的头文件目录下找那一个文件。(别的还会有怎样目录或然存放当前工程的头文件呢?稍后会讲。)

 

现行反革命,大家让main.cpp蕴涵了它想要的头文件,头文件内有它所需函数的科学注明,那么main.cpp中本来的那三行就剩下了:

void CalcTotal(int n);

void CalcAverage(int n);

char ToUpper(char c);

请删除。 然后,按F9,程序准确编写翻译,然后运维。这里我们不尊崇它的周转结果。

 

今昔来看一眼在CB中如何设定某一工程的头文件目录。

必须先说理解,在不短的一段时间内,我们并无需去实行此设置。对于CB提供的头文件,它们固定就在CB安装时自动积累的少数目录下,你就算记得包涵这一个头文件时,使用<>就可以。对于大家自已写的头文件,我们都把它们和工程文件存放在同一目录下,一时还尚未什么样理由要求把某部或少数头文件“扔”在别的目录下。所以,记住在富含自己的头文件时,对使用“”就可以。

先是保障当前CB正张开着方面包车型客车可怜例子工程。

接下来,主菜单: Project | Options 或按 Ctrl + Shift +
F11,张开“工程安装(Project
Options)”对话框,并切换成“目录与准绳(Directories/Conditionals)”页:

图片 7

 

图中关于目录的装置共六行,大家说里面常用的四行。

最主要的,当然是明日所说的“头文件目录”。当 CB 编译时,当它碰到那样一行:

 

#include “xxxx.h”

那正是说,它必须找到文件xxxx.h。要是,你写的是相对路线:#include
“c:\abc\123\xxxx.h”,那当然未有寻觅这一说,可是大家不会欣赏那样写程序,因为大家不期望源代换个岗位就得一一去改那多少个相对路径。事实上大家不也许把头文件随地放,总是恒久那么多少个目录,绝大好些个就三个:全数源文件和头文件都在日前工程所在目录下。这里能够加上,删除,修改部分索引地方,CB将按本设置中的目录次序去查找头文件。

请点击“头文件目录”左侧,带 “…”的小开关。出来二个新的对话框:

图片 8

($BCB) 表示Borland C++Builder 的设置目录。

 

在此处,你能够修改(Replace),扩张(Add),删除(Delete),调解次序(向上和向下的蓝箭头)各类头文件目录。CB6还提供了对无效目录的剖断,假设列表中列出的某部目录实际上并不设有对应的文书夹,则将以金黄突显,并且可以用”Delete
Invalid Paths”按键全体删减。

 

我们如何也不用做。点 Cancel, 放任正是。

 

其他目录的设定,操作完全等同。

 

有关在工程中如何使用头文件,我们就说这个了。

 

// 若是程序中引用了该变量,能够因而编写翻译,不过,

  1. extern 和 static

14.5 变量在三个源文件之间的接纳

前边讲的是,通过在头文件中宣示函数,能够达到规定的规范让这么些函数被其余文件共用的成效。同样地,变量也能够在多少个源文件之间“分享”。上边我们就要讲,怎样通过宣示变量,以高达让别的文件共用同三个变量的目标。

 

// 若无在有些文件中定义该变量的话,则链接会出错

 (1) extern 声明该变量在别的地点一度定义过了,在此间要选择十三分变量.
 (2) static 代表静态的变量,分配内部存款和储蓄器的时候, 存储在静态区,不存款和储蓄在栈上边.

14.5.1 变量评释

先说说“注明变量”。好像从前的课程只教过大家:定义变量,定义函数,证明函数,未有讲过“表明变量”啊?

 

作者们很早就学过哪些定义二个变量。(5.1.2)

 

比如:

 

//定义一个整型变量:

int age;

 

//然后,在后头的某处代码中选择那几个变量:

… …

age = 18;

cout << age << endl;

… …

 

 

不过,大家尚无境遇过什么声美赞臣个变量。那是因为,定义二个变量的还要,也就声称了贰个变量;绝大大多的时候,大家都以能够需求有些变量时,直接定义它。

 

明天的事态稍微分歧。大家要求在某些源文件中定义一个变量,然后,在此外二个源文件中央银行使这几个变量。

 

仍以前边 age 变量为例:

 

//大家在 A.cpp 文件中定义了那么些变量:

int age;

 

//然后,在 B.cpp 文件中要利用这些变量:

age = 18;

cout << age << endl;

 

难题就出去了:在编写翻译 B.cpp 文件时,编写翻译器会说:“age
这些变量未有定义啊?”——当编写翻译器在编写翻译B.cpp时,它并不领悟去A.cpp里去找有关 age 的定义。

那便是说,能否在B.cpp里再定义一回age变量呢?

 

//A.cpp文件中:

int age;

 

//B.cpp文件中:

int age;

age = 18;

cout << age << endl;

 

如此那般,单独编写翻译A.cpp,或B.cpp,都得以通过。但假设要编写翻译整个工程,编写翻译器又会报错:“怎么有八个age 变量的定义啊”?

不用作弄编写翻译器为何这么笨笨。C,C++是一门严俊的的Computer语言,我们无法仰望编写翻译器会“智能”地猜想技士的策划。

 

化解措施是,仅在一处概念变量,其余代码必要用到该变量,但不能够看到眼下的定义时,则改为“注明变量”。

 

扬言变量的语法:

extern 数据类型 变量名

 

和概念变量的语法比较,多了前方的 extern 这些重中之重字。

 

extern
意为“外来的”···它的效果在于告诉编写翻译器:有那么些变量,它可能不存在当前的公文中,但它必然要设有于工程中的某三个源文件中。

 

那就临近:微软集团在北京招人,微软的报名办法是:在新加坡的应聘者必须当天去面试,而异地应聘者则通过发e-mail先报名,然后未来再去面试。
在C,C++里,不处于当前源文件中的变量被叫作外界变量。比喻中,发e-mail就一定于表面变量在某壹个源中写个证明。注明什么呢?正是宣称“作者存在啊!固然笔者现在不在这里,不过小编实在存在!”

 

上例中,正确的代码应该这么写:

 

//A.cpp文件中:

int age;

 

//B.cpp文件中:

extern int age;

age = 18;

cout << age << endl;

 

变量 age
是在A.cpp文件里定义的,当B.cpp文件要选拔它时,必须先评释。那正是我们讲半天课的基本。

 

(有个别教材并不以为 extern int age;
是在宣称三个变量,它们把那也称之为是“定义变量”的一种,只但是它是概念了叁个名部变量。笔者以为那样认为不佳,一来它导致了学习者以为“变量能够重复定义”的荒谬感觉,二来它也招致了不联合,函数有“定义”和“注解”两种样式,而变量都不曾“表明”。

或是您会说,现在也不合併啊?函数证明未有“extern”,而变量却必要?呵呵,其实恰恰相反。函数证明本来也是需求几个“extern”的,举个例子:

 

extern void CalcTotal(int n);

您在代码里这么完全正确!只但是是因为函数注明和函数定义的格式差异非常的大,(申明未有函数体,定义则必须有函数体),所以这么些extern即便不写,也足以让编写翻译器认出来它是七个“表明”。结果就规定能够不写”extern”了。

而变量呢?

extern int age;     //那是宣称

int age;            //那是概念

你看看,不写”extern”可不行! 就靠它来不一致是概念仍旧评释了。

那样而已。)

 

// 因为链接目的文件的时候,须求该变量的合适地址.

    static 成效范围是中间连接的关联,
和extern有一点点相反.它和对象自己是分开积攒的,extern也是分手储存的,可是extern能够被其余的靶子用extern
援用,而static 不能,只同意对象自己用它.
具体差距首先,static与extern是一对“水火不容”的钱物,也便是说extern和static无法同一时间修饰贰个变量;其次,static修饰的全局变量表明与定义同一时候举办,相当于说当你在头文件中应用static声明了全局变量后,它也还要被定义了;最终,static修饰全局变量的作用域只好是自个儿的编译单元,也正是说它的“全局”只对本编写翻译单元有效,其余编写翻译单元则看不到它,如:
    (1) test1.h:
    #ifndef TEST1H
    #define TEST1H
    static char g_str[] = “123456”; 
    void fun1();
    #endif

14.5.2 八个文件中国共产党享变量的实例

 

做一个最简便的例子。新建二个调节台工程。然后再加三个单元文件。把工程存盘为Project1.bpr,把四个源文件分别存盘为Unit1.cpp、Unit2.cpp
(即,都选择暗中认可文件名)。

 

次第内容是:在 Unit1.cpp 钦赐义多个变量,即:int
age,并且,供给用户输入。在Unit2.cpp里,写一函数,OutputAgeText(),它根据age 的值, 输出一些文件。

 

请问,变量 age 在哪个地方定义?又在何地注脚?

 

概念内定是在 Unit1.cpp 文件里,而注解,则能够在
Unit2.cpp内直接注解(如上例中的中灰代码),也足以是在头文件 Unit1.h
里表明,然后在 Unit2.cpp 内使用 include 来含有 Unit1.h。
事实让,注明也得以放在
Unit2.h内。只要能让Unit2.cpp“看到”那个宣称就能够。这或多或少和函数的宣示一个道理。

 

笔者们应用放在Unit2.cpp中的方法,该格局所需代码如下:

 

//Unit1.cpp 内的重大代码:

 

#include <iostream.h>

#include <conio.h>

#pragma hdrstop

#include “Unit2.h”

… …

//—————————————————————————

int age; //全局变量,年龄

#pragma argsused

int main(int argc, char* argv[])

{

   cout << “请输入您的年华:” ;

   cin >> age;

 

   //调用Unit2.cpp中的函数,该函数依据age,作出相应输出

   OutAgeText();  

  

   getch();

   return 0;

}

//—————————————————————————

 

 

//Unit2.cpp 中的首要代码:

#include <iostream.h>

… …

extern int age;  //供给Unit1.cpp钦点义的变量

 

//报名到场“未有弯路”的学习者各行当,年龄段也各处不相同,在此,大家用那些函数作为共勉!

void OutAgeText()

{

   if(age < 15)

      cout  << “Computer要从儿童抓起!” << endl;

   else if(age < 25)

      cout << “青春年华,正是学习编程的纯金时代!” << endl;

   else if(age < 35)

      cout <<
“学习编制程序须求热情,更亟待理性!小编和您一样,也在这些年龄段!”<<
endl;

   else if(age < 45)

      cout <<
“活到老,学到老!何况您还未老。杀毒王王江民,不也在那个时候才先导学习计算机啊?”
<< endl;

   else

      cout << 
“前辈,只要您像学书法同样潜心学编制程序!您料定会有得到!” << endl;

}

//—————————————————————————
 

 

//Unit2.h 的首要代码:

 

//声明OutAgeText()函数,供Unit1.cpp使用

void OutAgeText();

//—————————————————————————
 

请我们落成这一个工程,直到能精确运营。

 

到现在我们赢得三个影象:当我们定义了叁个函数或变量之后,就好像具有的源代码文件中都能够动用它,只要你在动用在此之前写一下一见钟情的扬言。

那样会不会带来麻烦了?想象一下,你在A文件定义了三个变量: int i,
那么以往您在其余文件里就不可能再定义这些变量了!原因前边已经说过,编写翻译器(或链接器)会说有五个变量重名。函数也同样,纵然它有重运载飞机制,便那也只可以是有限制地同意函数重名。

 

实则,上例中的 int age
是三个全局变量。关于“全局”的分解,须要引起C,C++程序的另一话题:功用范围。那是下一章的剧情。在那一章里,大家将见到,一大半变量只在它必然的意义范围内“生存”,分化的法力范围的变量就足以毫无障碍地重名了。

安歇休憩(该点眼药水了···),然后学习本章附加一节。

 

/////////////////////////////////////////////////////

    (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全局变量时,都把它献身原来的书文件中而不是头文件,那样就不会给其余模块形成不须要的音信污染,同样记住那一个准绳呢!

#ifndef _FILE1_H

  1. extern 和const

#define _FILE1_H

  
C++中const修饰的全局常量占有跟static同样的特征,即它们只好功用于本编写翻译模块中,可是const能够与extern连用来声称该常量可以效用于此外编译模块中,
如extern const char g_str[];
    然后在原来的文章件中别忘了定义:     const char g_str[] = “123456”; 

#include <iostream.h>

   
所以当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″.

extern void FilePrint(int, int); //外界声明函数FilePrint

 

extern   m_nNum ;         //注明变量 m_nNum,常写成extern int m_nNum

引文二、(首要偏侧知情和实用)

 

 

#endif

  1. #include “stdafx.h”  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. extern int i;  
  6. extern void func();  
  7. int _tmain(int argc, _TCHAR* argv[])//typedef wchar_t     _TCHAR;#define _tmain      wmain  
  8. {  
  9.     i = 0;  
  10.     func();  
  11.     return 0;  
  12. }  
  13.   
  14. int i;  
  15.   
  16. void func()  
  17. {  
  18.     i++;  
  19.     cout << “i = ” << i << endl;  
  20. }  

 

 

file1.cpp

   
上边代码中变量i和函数func在文件末尾定义,所以变量须要使用extern关键字告诉编写翻译器,变量在别的地点定义。extern
int i小编本来认为extern
i就能够,结果编写翻译器报错,留神想下真的应该,不然编写翻译器不知道i是哪些项目标数据,又怎么能看清i
= 0是或不是是一个准确的赋值语句呢?

#include “file1.h”

 

 

    那么定义在此外文件中的函数和变量,如何通过extern关键字调用吗?

int m_nNum = 1;
//若无概念该变量,则main.cpp能够由此编写翻译,但顺序链接出错

    首先,定义在其它文件中的函数和变量,能够运用二种方法调用:

void FilePrint(int a, int b)

        一、使用头文件调用,那时候,函数和变量必须在头文件中定义和评释。

{

       
二、使用extern关键字调用,那时候函数和变量在.cpp恐怕.c文件中定义和注脚。

 

    看上边四个例证:

       cout << “/n the num is ” << a << “and the
double is “

    devVar.cpp函数中定义:

               << b <<endl;

       

       return;

[cpp] view
plain copy

}

 

 

  1. #include “stdafx.h”  
  2.   
  3. int i;  

main.cpp

 

#include “file1.h”

    extern.cpp中

 

[cpp] view
plain copy

int main(int i, char b)

 

{

  1. // extern.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include “stdafx.h”  
  5. #include <iostream>  
  6. using namespace std;  
  7.   
  8. extern int i;  
  9. extern void func();  
  10. int _tmain(int argc, _TCHAR* argv[])//typedef wchar_t     _TCHAR;#define _tmain      wmain  
  11. {  
  12.     i = 0;  
  13.     func();  
  14.     return 0;  
  15. }  
  16.   
  17. void func()  
  18. {  
  19.     i++;  
  20.     cout << “i = ” << i << endl;  
  21. }  

      

 

       cout << ” the first parm is “<< i

   编写翻译工程,程序输出:i =
1,这里使用extern关键字注解在任何cpp文件中定义的变量和函数。

               << ” and the second char is ” << b
<<endl;

 

       FilePrint( m_nNum, 2*m_nNum);

    #include <filensme> —
将filename文件中的内容插入到新的文书中。

       return 0;

    deVar.h文件中代码为

}

[cpp] view
plain copy

 

 

在头文件中,证明了函数FilePrint和变量m_nNum,在file1.cpp中定义了那多少个变量。若无在file1.cpp中定义那七个变量,那么,main.cpp能够由此编写翻译,不过程序链接会出错。

  1. #include <stdio.h>  
  2.   
  3. int i = 1;  
  4.   
  5. void func()  
  6. {  
  7.     printf(“%d”,i++);  
  8. }  

变量的扬言和概念往往不便于分清,好多时候注脚的还要就定义了。如上例所示,若无在头文件file1.h中阐明m_nNum,也未曾在file1.cpp中定义,而是在main.cpp文件中宣示全局变量:

     函数func修改全局变量i的值并出口。

int m_nNum;//表明的还要定义,编写翻译器给该变量分配了上空

    extern.cpp文件内容为:

int main(int i, char b)

[cpp] view
plain copy

{

 

              m_nNum = 1;

  1. #include “stdafx.h”  
  2. #include <stdio.h>  
  3. #include <iostream>  
  4. using namespace std;  
  5. #include “devVar.h”  
  6. //extern int i;  
  7. //extern void func();  
  8.   
  9. int main(void)  
  10. {  
  11.     for (int x = 0;x < 10; x++)  
  12.     {  
  13.         func();  
  14.     }  
  15. }  

              cout << ” the first parm is “<< i

先后输出1,2,3,4,5,6,7,8,9,10,这里#include <filname.h>
包蕴定义在其他头文件中的函数和变量,在来看二个例证。

                      << ” and the second char is ” << b
<<endl;

   

              FilePrint( m_nNum, 2*m_nNum);

[cpp] view
plain copy

              return 0;

 

}

  1. // extern.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include “stdafx.h”  
  5. #include <iostream>  
  6. using namespace std;  
  7.   
  8. extern int i;  
  9. extern int  func(int);//这里extern必需的,函数定义在其余cpp文件中  

函数的证明和概念比较易于区分。注解的时候不要写函数体,只需求规定函数名和参数就足以了;函数的概念需求函数体的兑现。

[cpp] view
plain copy

如:void FilePrint(int, int)
告诉编写翻译器函数FilePrint已经宣称,它有五个int型的输入参数,在宣称中,能够不写出形参的称谓。

 

而 void FilePrint(int a, int b) {
}表示函数已经定义,就算它是三个空函数。

  1. int _tmain(int argc, _TCHAR* argv[])//typedef wchar_t     _TCHAR;#define _tmain      wmain  
  2. {  
  3.     i = 100;  
  4.     func(i);  
  5.     return 0;  
  6. }  

 

    devVar.cpp文件中内容为:

extern 关键字

   

extern
告诉编写翻译器,该变量是在表面定义的,在本例中,当编写翻译器对mail.cpp举行编写翻译时,它告诉编写翻译器,m_nNum和FilePrint是在任何文件
(file1.cpp)中定义的,链接的时候再到别的obj文件中寻觅它们的地址。对于编写翻译器来说,extern
告诉了它变量的名字。如在头文件file1.h中,只要求写成extern m_nNum
就足以了(当然也得以写成extern int m_nNum)。

[cpp] view
plain copy

别的要稳重,并不是装有的变量都能够用extern
注脚,只有全局非静态变量技能声称为extern。

 

如在file1.cpp中,static int m_nNum,编写翻译会出错。

  1. #include “stdafx.h”  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. int i;  
  6.   
  7. int func(int a)  
  8. {  
  9.     i = a;  
  10.     cout << “i = ” << i << endl;  
  11.     return 0;  
  12. }  

    那样,同样是出口了i= 100。

    能够使用extern援用其余cpp文件中定义的函数表明了三个标题:

   
即使三个工程现编写翻译cpp文件,在把多个目的文件链接成为可实施文件,而八个或八个文件中,定义了平等的全局变量,那么,程序编写翻译的时候不会报错,因为编写翻译器单独编写翻译每一个文件,在链接可施行文件的时候,由于多个指标文件中带有一样的全局变量,而生成可试行文件的时候,任何文件中定义的全局变量对其余指标文件都以可知的,此时是因为变量定义冲突而发生错误。看下边包车型地铁代码:

   

[cpp] view
plain copy

 

  1. // extern.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include “stdafx.h”  
  5. #include <iostream>  
  6. using namespace std;  
  7.   
  8. int i;  
  9. extern int  func(int);//这里extern是必须的函数定义在其他cpp文件中  
  10. int _tmain(int argc, _TCHAR* argv[])//typedef wchar_t     _TCHAR;#define _tmain      wmain  
  11. {  
  12.     i = 100;  
  13.     func(i);  
  14.     return 0;  
  15. }  

 

devVar.cpp文件中,内容为:

[cpp] view
plain copy

 

  1. #include “stdafx.h”  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. int i;  
  6.   
  7. int func(int a)  
  8. {  
  9.     i = a;  
  10.     cout << “i = ” << i << endl;  
  11.     return 0;  
  12. }  

   
单独compile任何多个cpp文件都以对的,不过 编写翻译工程,生成可试行文件的时候报错:

    1>LINK : D:\vctest\extern\Debug\extern.exe not found or not
built by the last incremental link; performing full link
1>devVar.obj : error LNK2005: “int i” (?i@@3HA) already defined in
extern.obj
1>D:\vctest\extern\Debug\extern.exe : fatal error LNK1169: one or
more multiply defined symbols found

    原因是:四个.cpp文件中都定义了全局变量i,变量重复定义了。

 

    PS:定义在.h文件中的函数和变量不能够使用extern变量评释,原因是#include
<filename>在预编写翻译的时候将.h文件中的内容插入了cpp文件中,由此编写翻译器找得到在别的.h文件中定义的变量或然函数。编写翻译的时候,只编写翻译cpp文件的开始和结果,.h文件时不参加工编织译,假设使用extern证明在.h文件中定义的变量可能函数,那么声明为extern的变量和函数在其它.cpp文件中找不到,因而先后编译的时候就产生了不当。

 

 

chapter2,如何混合编写翻译C语言和C++

   
实际开辟进度中,C++中会调用C与语言编写的代码,小编在网络方面找到一篇写得很好的稿子

   

   就着地点的例证,作者动用C语言采取二种办法重写了弹指间。

  
方法一、全局函数和变量在devVar.c文件中贯彻,在extern.cpp文件中使用extern关键字申明在devVar.c文件中定义的函数和变量。

   devVar.c文件的代码如下所示:

   

[cpp] view
plain copy

 

  1. #include <stdio.h>  
  2.   
  3. int i = 1;  
  4.   
  5. void func()  
  6. {  
  7.     printf(“%d”,i++);  
  8. }  

   extern.cpp文件中代码如下所示:

   

[cpp] view
plain copy

 

  1. #include “stdafx.h”  
  2. #include <stdio.h>  
  3. #include <iostream>  
  4. using namespace std;  
  5. //#include “devVar.h”  
  6. //extern int i;  
  7. //extern void func();  
  8.   
  9. extern “C”  
  10. {  
  11.     extern int i;  
  12.     extern void func();  
  13.     //#include “devVar.h”   
  14. }  
  15. int main(void)  
  16. {  
  17.     for (int x = 0;x < 10; x++)  
  18.     {  
  19.         func();  
  20.     }  
  21. }  

    所以在C++文件中编写翻译C文件要求使用extern “C”关键字,注脚语法如下所示

    extern “C”

    {

        接纳C语言完结的剧情

    }

 

    方法二、

   
在devVar.h文件中贯彻C代码(即devVar.h作为C语言头文件),在.cpp文件中含有C语言头文件。

    devVar.h头文件内容为:

   

[cpp] view
plain copy

 

  1. #include <stdio.h>  
  2.   
  3. int i = 1;  
  4.   
  5. void func()  
  6. {  
  7.     printf(“%d”,i++);  
  8. }  

    extern.cpp文件内容如下所示

   

[cpp] view
plain copy

 

  1. #include “stdafx.h”  
  2. #include <stdio.h>  
  3. #include <iostream>  
  4. using namespace std;  
  5. //#include “devVar.h”  
  6. //extern int i;  
  7. //extern void func();  
  8.   
  9. extern “C”  
  10. {  
  11.     //extern int i;  
  12.     //extern void func();  
  13.     #include “devVar.h”   
  14. }  
  15. int main(void)  
  16. {  
  17.     for (int x = 0;x < 10; x++)  
  18.     {  
  19.         func();  
  20.     }  
  21. }  

    在这之中,包涵C语言头文件的措施为:

[cpp] view
plain copy

 

  1. extern “C”  
  2. {  
  3.     //extern int i;  
  4.     //extern void func();  
  5.     #include “devVar.h”   
  6. }  

 

   
写到这里,楼主又产生了三个疑云,上面的例证讲的是C++调用C落成的代码,那如若是C调用C++编写的代码呢?

    楼主作了如下改动:

    devVar.cpp代码为:   

[cpp] view
plain copy

 

  1. #include <stdio.h>  
  2.   
  3. int i = 1;  
  4.   
  5. void func()  
  6. {  
  7.     printf(“%d”,i++);  
  8. }  

    extern.c文件代码为

[cpp] view
plain copy

 

  1. #include <stdio.h>  
  2.   
  3. extern int i;  
  4. extern void func();  
  5.   
  6. int main(void)  
  7. {  
  8.     int x = 0;  
  9.     for (;x < 10; x++)  
  10.     {  
  11.         func();  
  12.     }  
  13. }  

    单独编写翻译每一个文件都经过,链接声称可施行文件的时候报错:

    1>extern.obj : error LNK2019: unresolved external symbol _func
referenced in function _main,表明.c文件中extern void
func(),依据C编译的条条框框,获得函数_func,而devVar.cpp文件采取C++编写翻译方式,获得的函数为XX·!_func(具体楼主也不明白哈),那样链接的时候函数自然找不到,那怎么化解呢?

    供给在devVar.cpp中,明显调用extern
“C”关键字,注解cpp文件中有关代码,要求遵照C的主意来变化,修改devVar.cpp文件如下所示:

   

[cpp] view
plain copy

 

  1.     #include <stdio.h>  
  2.   
  3.     int i = 1;  
  4.   
  5.   
  6. extern “C” void func()  
  7.     {  
  8.         printf(“%d”,i++);  
  9.     }  

     此时,除了须要使用extern
“C”注解编写翻译的时候利用C情势编译外,.cpp文件中的代码能够依据C++方式编写,举例

     devVar.cpp根据上边方式写,也是天经地义的。

    

[cpp] view
plain copy

 

  1. #include “stdafx.h”  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. int i = 1;  
  6.   
  7. extern “C” void func()  
  8.     {  
  9.         cout << “i = ” << i++ << endl;  
  10.     }  

相关文章

Leave a Reply

电子邮件地址不会被公开。 必填项已用*标注