• 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的内容:
       

  • 相关阅读:
    Kubernetes 集成研发笔记
    Rust 1.44.0 发布
    Rust 1.43.0 发布
    PAT 甲级 1108 Finding Average (20分)
    PAT 甲级 1107 Social Clusters (30分)(并查集)
    PAT 甲级 1106 Lowest Price in Supply Chain (25分) (bfs)
    PAT 甲级 1105 Spiral Matrix (25分)(螺旋矩阵,简单模拟)
    PAT 甲级 1104 Sum of Number Segments (20分)(有坑,int *int 可能会溢出)
    java 多线程 26 : 线程池
    OpenCV_Python —— (4)形态学操作
  • 原文地址:https://www.cnblogs.com/day-dayup/p/3567763.html
Copyright © 2020-2023  润新知