因项目须求,供给对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童话》,是把它们放在同二个抽屉里吧?依旧分开放到七个抽屉里?笔者以为前面一个是比较好的选项。因为大家经常希望家里看《格林童话》的人,最佳不要去看《红楼》。

前后相继也一模二样,最佳把不一致的逻辑达成,放到分裂的源文件中。

 

上面我们做三个实例。例子的代码大家都已经学过。指标是贯彻二个得以求总计值和平均值的次第。

遵照大家以往所学的场馆,小编把那个工程中的代码分为五个源代码:

以此:主程序。就是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和第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里的代码,依旧看不到它们。想一想大家此前说的“请修理工科”的比喻。现在状态是:在你所住的小区,以致即使同一楼道里,就有三个TV修理工科,顾虑痛你们互不认知,所以当您电视机坏了,想“调用”二个修缮工作时间,你要么找不到修理工科。哎!若是有它的片子就好了。

让大家尝试看,按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在此以前出席。

 

// 表明一(Wissu)个变量就是告诉编译器,那些变量名已经存在

    (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

 

当编写翻译第二回编写翻译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++是一门严酷的的计算机语言,我们不可能仰望编译器会“智能”地预计程序猿的攻略。

 

减轻形式是,仅在一处概念变量,别的代码供给用到该变量,但力不可能及看到眼下的定义时,则改为“注明变量”。

 

证明变量的语法:

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 <<
“活到老,学到老!並且你还未老。杀毒王王江民,不也在这年才开头读书Computer啊?”
<< 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.     }  

相关文章