• C语言extern关键字使用


    在chinaunix上看见一篇转载的文章,觉得特别好,关于extern使用的解释:

    参考链接:http://doc.chinaunix.net/CPP/201206/2248432.shtml

    在C语言中,修饰符extern用在变量或者函数的声明前,用来说明"此变量/函数是在别处定义的,要在此处引用".
       
       1. extern修饰变量的声明。举例来说,如果文件a.c需要引用b.c中变量int v,就可以在a.c中声明extern int v,然后就可以引用变量v.这里需要注意的是,被引用的变量v的链接属性必须是外链接(external)的,也就是说a.c要引用到v,不只是取决于在a.c中声明extern int v,还取决于变量v本身是能够被引用到的。这涉及到c语言的另外一个话题--变量的作用域。能够被其他模块以extern修饰符引用到的变量通常是全局变量。还有很重要的一点是,extern int v可以放在a.c中的任何地方,比如你可以在a.c中的函数fun定义的开头处声明extern int v,然后就可以引用到变量v了,只不过这样只能在函数fun作用域中引用v罢了,这还是变量作用域的问题。对于这一点来说,很多人使用的时候都心存顾虑。好像extern声明只能用于文件作用域似的。
       
       2. extern修饰函数声明。从本质上来讲,变量和函数没有区别。函数名是指向函数二进制块开头处的指针。如果文件a.c需要引用b.c中的函数,比如在b.c中原型是int fun(int mu),那么就可以在a.c中声明extern int fun(int mu),然后就能使用fun来做任何事情。就像变量的声明一样,extern int fun(int mu)可以放在a.c中任何地方,而不一定非要放在a.c的文件作用域的范围中。 对其他模块中函数的引用,最常用的方法是包含这些函数声明的头文件。使用extern和包含头文件来引用函数有什么区别呢?extern的引用方式比包含头文件要简洁得多!extern的使用方法是直接了当的,想引用哪个函数就用extern声明哪个函数。这大概是KISS原则的一种体现吧!这样做的一个明显的好处是,会加速程序的编译(确切的说是预处理)的过程,节省时间。在大型C程序编译过程中,这种差异是非常明显的。
       
       3. 此外,extern修饰符可用于指示C或者C++函数的调用规范。比如在C++中调用C库函数,就需要在C++程序中用extern "C"声明要引用的函数。这是给链接器用的,告诉链接器在链接的时候用C函数规范来链接。主要原因是C++和C程序编译完成后在目标代码中命名规则不同。
       
       二:了解了上面的基本原理,下面深入一下。如下:
       
       内容清单:
       
       1. 用extern声明外部变量
       
       (1)在一个文件内声明的外部变量
       
       (2)在多个文件中声明外部变量
       
       (3)在多个文件中声明外部结构体变量
       
       2. 用extern声明外部函数
       
       3. 总结
       
       1.  用extern声明外部变量
       
       定义:外部变量是指在函数或者文件外部定义的全局变量。外部变量定义必须在所有的函数之外,且只能定义一次。
       
       (1)      在一个文件内声明的外部变量
       
       作用域:如果在变量定义之前要使用该变量,则在用之前加extern声明变量,作用域扩展到从声明开始,到本文件结束。
       
       例子:
       
     

    #include <stdio.h>
          
       int max(int x,int y); //函数提前声明
          
       int main(int argc,char *argv[ ] )
          
       {
          
       int result;
          
       extern int X; //外部变量声明
          
       extern int Y;
          
       result = max(X,Y);
          
       printf("the max value is %dn",result);
          
       return 0;
          
       }
          
       int X = 10; //定义外部变量
          
       int Y = 20;
          
       int max(int x, int y)
          
       {
          
       return (x>y ? x : y);
          
       }


       
       其中,用extern声明外部变量时,类型名可以省略。例如,"extern int X;",可以改写成"extern X;".
       
       小结:这种用方法简单,实用性不大。

    (2)      在多个文件中声明外部变量
       
       作用域:如果整个工程由多个文件组成,在一个文件中想引用另外一个文件中已经定义的外部变量时,则只需在引用变量的文件中用extern关键字加以声明即可。可见,其作用域从一个文件扩展到多个文件了。
       
       例子:
       
       文件a.c的内容:
       
     

    #include <stdio.h>
          
       int BASE=2; //变量定义
          
       int exe(int x); //外部函数提前声明
          
       int main(int argc, char *agrv[])
          
       {
          
       int a=10;
          
       printf("%d^%d = %dn",BASE,a,exe(a));
          
       return 0;
          
       }
          
       文件b.c的内容:
          
       #include <stdio.h>
          
       extern BASE; //外部变量声明
          
       int exe(int x)
          
       {
          
       int i;
          
       int ret=1;
          
       for(i=0;i<x;i++)
          
       {
          
       ret*=BASE;
          
       }
          
       return ret;
          
       }


       
       利用gcc工具编译gcc a.c b.c –o demo,再运行。/demo,结果为2^10 = 1024.其中,在a.c文件中定义BASE=2,在b.c中引用BASE时,需要用extern关键字声明其为外部变量,否则编译会找不到该变量。
       
       小结:对于多个文件的工程,可以采用这种方法来操作。实际工程中,对于模块化的程序文件,在其文件中可以预先留好外部变量的接口,也就是只采用extern声明变量,不定义变量,也通常在模块程序的头文件中声明,在使用该模块时,只需要在使用时定义一下即可,如上述b.c文件,做好相应的函数接口,留好需要改变BASE值的声明,在需要使用该模块时,只需要在调用的文件中定义具体的值即可。
       
       引用外部变量和通过函数形参值传递变量的区别:用extern引用外部变量,可以在引用的模块内修改其值,而形参值传递的变量则不能修改其值,除非是地址传递。
       
       因此,如果多个文件同时对需要应用的的变量进行同时操作,可能会修改该变量,类似于形参的地址传递,从而影响其他模块的使用,因此,要慎重使用。
       
       (3)      在多个文件中声明外部结构体变量
       
       前面一节中,只是适合一般变量的外部声明,但是对于声明外部结构体变量时,则有些不同,需要加以注意。
       
       例子:
       
       文件a.c的内容:
       

    #include <stdio.h>
        
     #include "b.h"
        
     #include "c.h"
        
     A_class local_post={1,2,3}; //全局变量
        
     A_class next_post={10,9,8}; //全局变量
        
     int main(int argc,char *argv[])
        
     {
        
     A_class ret;
        
     print("first point",local_post);
        
     print("second point",next_post);
        
     ret=fun(local_post,next_post);
        
     printf("the vector is (%d,%d,%d)n",ret.x,ret.y,ret.z);
        
     return 0;
        
     }


       
       文件b.h的内容:
       

  • 相关阅读:
    一起做一款开源软件吧--开源软件诞生1
    牛客-紫魔法师(仙人掌染色-判奇环)
    牛客编程巅峰赛S1第12场 王者C-椭圆曲线(快速乘的运用)
    牛客编程巅峰赛S1第12场 王者B-上上下下(DP)
    牛客编程巅峰赛S1第12场 王者A-锻炼身体(树上追击问题)
    CSUSTOJ 1127-区间方差(线段树)
    Codeforces 1398C- Good Subarrays(区间值为0的个数变形-思维)
    CSUSTOJ 4000-你真的会数据结构吗?(状压+素数分解)
    牛客练习赛67 F-牛妹的苹果树(树上最远点对/区间带权直径-线段树+LCA)
    牛客练习赛67 E-牛妹游历城市(拆位最短路)
  • 原文地址:https://www.cnblogs.com/day-dayup/p/3567763.html
Copyright © 2020-2023  润新知