您的位置 首页 被动

extern和头文件

最近接手了一个项目的改进,其中一个任务就是对源代码进行优化。所以想把所有的文件整理成条理清晰,功能独立的一个个模块。而原先的程序当

最近接手了一个项目的改善,其间一个使命便是对源代码进行优化。所以想把一切的文件整理成条理清晰,功用独立的一个个模块。而原先的程序傍边,每一个简略的源文件都包容了十几个头文件,由于一个头文件中包容了其它的几个头文件,而其它的头文件又包容了几个头文件。或许关于某一个源文件来说,这个头文件有必要包容其他的几个头文件,可关于其他一些源文件来说却没有必要。而这样的成果便是编译衔接后,每个源文件下都包容了十几个头文件,最终成为了一张蜘蛛网,你连减都减不掉。我试着用声明外部函数的方法替换包容头文件的方法,只能对几个简略的源文件进行了优化。

所以,想从这个问题下手,好好研究一下关键字“extern”和头文件。

查了一些材料和一些书。

extern能够置于变量或许函数前,以表明变量或许函数的界说在其他文件中,提示编译器遇到此变量和函数时在其他模块中寻觅其界说。其他,extern也可用来进行链接指定。

extern变量

在一个源文件里界说了一个数组:char a[6];

  在其他一个文件里用下列句子进行了声明:extern char *a;

  请问,这样能够吗?

  答案与剖析:

  1)、不能够,程序运转时会告知你不合法拜访。原因在于,指向类型T的指针并不等价于类型T的数组。extern char *a声明的是一个指针变量而不是字符数组,因此与实践的界说不同,然后形成运转时不合法拜访。应该将声明改为extern char a[ ]。

  2)、比如剖析如下,假如a[] = “abcd”,则外部变量a=0x12345678 (数组的开始地址),而*a是从头界说了一个指针变量a的地址可能是0x87654321,直接运用*a是过错的.

3)、这提示咱们,在运用extern时分要严厉对应声明时的格局,在实践编程中,这样的过错层出不穷。

4)、extern用在变量声明中常常有这样一个效果,你在*.c文件中声明晰一个大局的变量,这个大局的变量假如要被引证,就放在*.h中并用extern来声明。

编译、链接

1、 声明外部变量

现代编译器一般选用按文件编译的方法,因此在编译时,各个文件中界说的大局变量是彼此通明的,也便是说,在编译时,大局变量的可见域约束在文件内部。下面举一个简略的比如。创立一个工程,里边含有A.cpp和B.cpp两个简略的C++源文件:

  //A.cpp

  int i;

  void main()

  {

  }

  //B.cpp

  int i;

  这两个文件极为简略,在A.cpp中咱们界说了一个大局变量i,在B中咱们也界说了一个大局变量i。

  咱们对A和B别离编译,都能够正常经过编译,可是进行链接的时分,却呈现了过错,过错提示如下:

  Linking…

  B.obj : error LNK2005: “int i” (?i@@3HA) already defined in A.obj

  Debug/A.exe : fatal error LNK1169: one or more multiply defined symbols found

  Error executing link.exe.

  A.exe – 2 error(s), 0 warning(s)

  这便是说,在编译阶段,各个文件中界说的大局变量彼此是通明的,编译A时察觉不到B中也界说了i,相同,编译B时察觉不到A中也界说了i。

  可是到了链接阶段,要将各个文件的内容“合为一体”,因此,假如某些文件中界说的大局变量名相同的话,在这个时分就会呈现过错,也便是上面提示的重复界说的过错。

  因此,各个文件中界说的大局变量名不行相同。

  在链接阶段,各个文件的内容(实践是编译发生的obj文件)是被合并到一同的,因此,界说于某文件内的大局变量,在链接完结后,它的可见规模被扩展到了整个程序。

  这样一来,按道理说,一个文件中界说的大局变量,能够在整个程序的任何当地被运用,举例说,假如A文件中界说了某大局变量,那么B文件中应能够运用该变量。修正咱们的程序,加以验证:

  //A.cpp

  void main()

  {

  i = 100; //企图运用B中界说的大局变量

  }

  //B.cpp

  int i;

  编译成果如下:

  Compiling…

  A.cpp

  C:Documents and Settingswangjian桌面 ry externA.cpp(5) : error C2065: i : undeclared identifier

  Error executing cl.exe.

  A.obj – 1 error(s), 0 warning(s)

  编译过错。

  其实呈现这个过错是意料之中的,由于:文件中界说的大局变量的可见性扩展到整个程序是在链接完结之后,而在编译阶段,他们的可见性仍局限于各自的文件。

  编译器的目光不行久远,编译器没有能够意识到,某个变量符号尽管不是本文件界说的,可是它可能是在其它的文件中界说的。

  尽管编译器不行远见,可是咱们能够给它提示,协助它来处理上面呈现的问题。这便是extern的效果了。

  extern的原理很简略,便是告知编译器:“你现在编译的文件中,有一个标识符尽管没有在本文件中界说,可是它是在其他文件中界说的大局变量,你要放行!”

  咱们为上面的过错程序加上extern关键字:

  //A.cpp

  extern int i;

  void main()

  {

  i = 100; //企图运用B中界说的大局变量

  }

  //B.cpp

  int i;

顺畅经过编译,链接。

定论1、各个文件中界说的大局变量不能够同名,编译的时分不会有问题,衔接的时分会呈现问题。所以在编程规范中,假如是界说大局变量,最好加上文件约束区域。

定论2、引证一个外部的大局变量的时分不能够赋初值。

定论3、声明一个外部函数的时分,不需要加extern来润饰也是能够的。经过实践比如查验经过,还在不同的编译环境下调试过。

举个比如a.c文件中有5个函数,每一个前面界说的函数都引证了后边界说的函数,因此,咱们界说了一个a.h文件,寄存一切a.c文件中的函数声明,编译运转肯定没有问题。那么运转的思路是这样的。当第一个函数调用后边的函数的时分,由于a.h文件中现已声明晰函数,所以能够履行下去,那么相关于a.h文件来说,他怎样找到a.c文件中的函数界说呢?此刻在a.h文件中的函数声明可没有运用extern来润饰。反过来,假如是b.c文件引证了a.h来调用a.c的函数。所以,当b.c文件要运用a.c中的函数时,只需要声明函数原型,而不需要加extern来润饰。亦可。

函数

定论4、在不同的文件中,不能够声明同名的函数。C言语不支撑重载。

extern函数1

  常见extern放在函数的前面成为函数声明的一部分,那么,C言语的关键字extern在函数的声明中起什么效果?

  答案与剖析:

  假如函数的声明中带有关键字extern,仅仅是暗示这个函数可能在其他源文件里界说,没有其它效果。即下述两个函数声明没有显着的差异:

  extern int f(); 和int f();

  当然,这样的用途仍是有的,便是在程序中替代include “*.h”来声明函数,在一些杂乱的项目中,我比较习气在一切的函数声明前增加extern润饰。

  extern 函数2

  当函数供给方单方面修正函数原型时,假如运用方不知情持续沿袭本来的extern声明,这样编译时编译器不会报错。可是在运转过程中,由于少了或许多了输入参数,往往会形成体系过错,这种状况应该怎么处理?

  答案与剖析:

  现在业界针对这种状况的处理没有一个很完美的计划,一般的做法是供给方在自己的xxx_pub.h中供给对外部接口的声明,然后调用方include该头文件,然后省去extern这一步。以防止这种过错。

  宝剑有双锋,对extern的运用,不同的场合应该挑选不同的做法。

  extern “C”

  在C++环境下运用C函数的时分,常常会呈现编译器无法找到obj模块中的C函数界说,然后导致链接失利的状况,应该怎么处理这种状况呢?

  答案与剖析:

  C++言语在编译的时分为了处理函数的多态问题,会将函数名和参数联合起来生成一个中心的函数称号,而C言语则不会,因此会形成链接时找不到对应函数的状况,此刻C函数就需要用extern “C”进行链接指定,这告知编译器,请坚持我的称号,不要给我生成用于链接的中心函数名。

  下面是一个规范的写法:

  //在.h文件的头上

  #ifdef __cplusplus

  #if __cplusplus

  extern “C”{

  #endif

  #endif

  …

  …

  //.h文件完毕的当地

  #ifdef __cplusplus

  #if __cplusplus

  }

  #endif

  #endif

  C++中extern c的深层探究

  C++言语的创立初衷是“a better C”,可是这并不意味着C++中相似C言语的大局变量和函数所选用的编译和衔接方法与C言语完全相同。作为一种欲与C兼容的言语,C++保留了一部分过程式言语的特色(被世人称为“不彻底地面向对象”),因此它能够界说不属于任何类的大局变量和函数。可是,C++毕竟是一种面向对象的程序设计言语,为了支撑函数的重载,C++对大局函数的处理方法与C有显着的不同。

  2.从规范头文件说起

  某企业从前给出如下的一道面试题:

  面试题

  为什么规范头文件都有相似以下的结构?

  #ifndef __INCvxWorksh

  #define __INCvxWorksh

  #ifdef __cplusplus

  extern “C” {

  #endif

  

  #ifdef __cplusplus

  }

  #endif

  #endif

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/ziliao/beidong/258766.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部