C语言中extern关键字详解

来源:互联网 发布:网络监控用光纤方案图 编辑:程序博客网 时间:2024/04/20 04:54

内容清单:

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 %d\n",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 = %d\n",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的内容:

#ifndef __B_H

#define __B_H

#if   1

typedef struct{

        int x;

        int y;

        int z;

}A_class;

#endif

extern A_class local_post;  //外部结构体变量声明

extern A_class fun(int x,int y,int z);       //接口函数声明

#endif

文件b.c的内容:

#include <stdio.h>

#include "b.h"

A_class fun(A_class first,A_class next)

{

        A_class ret;

        ret.x=next.x-first.x;

        ret.y=next.y-first.x;

        ret.z=next.z-first.z;

        return (ret);

}

文件c.h的内容:

       #ifndef __C_H

#define __C_H

extern int print(char *,A_class post);

#endif

       文件c.c的内容:

              #include <stdio.h>

#include "b.h"

int print(char *str,A_class post)

{

        printf("%s : (%d,%d,%d)\n",str,post.x,post.y,post.z);

        return 0;

}

利用gcc工具编译gcc a.c b.c c.c–o demo,再运行./demo,结果为

first point : (1,2,3)

second point : (10,9,8)

the vector is (9,8,5)

       小结:在a.c文件中定义全局变量A_class local_post结构体,并且调用b.c中的接口函数A_class fun(int x,int y,int z)c.cint print(char *str,A_class post),在b.h中声明外部结构体变量local_post,同时,需要对其类型A_class进行实现,在b.h文件中,如果屏蔽掉A_class的实现,而在b.h以外的文件中实现,此时编译时就会出错,由于c.c文件中用到A_class定义的类型,所以需要在该文件中包含b.h

       这里需要说明的是,如果调用外部结构体等多层结构体变量时,需要对这种变量进行实现,使用时,加上模块的头文件即可,否则会报错。

       实际工程中,模块化程序文件,一般提供一个.c和一个.h文件,其中.h文件被.c文件调用,.h文件中实现。

2.extern声明外部函数

a.      定义函数时,在函数返回值类型前面加上extern关键字,表示此函数时外部函数,可供其他文件调用,如extern int func (int x,int y)C语言规定,此时extern可以省略,隐形为外部函数。

b.      调用此函数时,需要用extern对函数作出声明。

作用域:使用extern声明能够在一个文件中调用其他文件的函数,即把被调用函数的作用域扩展到本文件。C语言中规定,声明时可以省略extern

例子:

文件a.c的内容:

#include <stdio.h>

#include "b.h"

int main()

{

        int x=10,y=5;

        printf("x = 10,y = 5\n");

        printf("x + y = %d\n",add(x,y));

        printf("x - y = %d\n",sub(x,y));

        printf("x * y = %d\n",mult(x,y));

        printf("x / y = %d\n",div(x,y));

        return 0;

}

文件b.h的内容:

#ifndef __F_H

#define __F_H

extern int add(int x,int y);

extern int sub(int x,int y);

extern int mult(int x,int y);

extern int div(int x,int y);

#endif

文件b.c的内容:

#include <stdio.h>

int add(int x,int y)

{

        return(x+y);

}

int sub(int x,int y)

{

        return(x-y);

}

int mult(int x,int y)

{

        return(x*y);

}

int div(int x,int y)

{

        if(y!=0)

        {

                return(x/y);

        }

        printf("mult() fail!the second para can not be zero!\n ");

        return(-1);

}

利用gcc工具编译gcc a.c b.c –o demo,再运行./demo,结果为

x = 10,y = 5

x + y = 15

x - y = 5

x * y = 50

x / y = 2

小结:由上面简单的例子可以看出,在b.h文件中声明好b.c的函数,使用时,只需要在a.c中包含#include “b.h”头文件即可,这样就可以使用b.c的接口函数了,在实际工程中,通常也是采用这种方式,.c文件中实现函数,.h文件中声明函数借口,需要调用.c文件的函数接口时,只需包含.h头文件即可。

 

3. 总结

在实际工程中,有两种情况比较多。一是利用extern只声明外部函数,不需要传递需要外部声明的变量,一个模块化接口文件对应一个声明接口的头文件,需要调用接口函数时,只需要包含其头文件。二是利用用extern声明外部函数,同时声明需要传递的外部变量,做法和第一种情况一样,声明都放在头文件中,但是,模块文件也需要包含该头文件。另外,如果结构体等比较复杂的变量,则需要包含其定义的头文件。另外,定义的外部变量属于全局变量,其存储方式为静态存储,生存周期为整个程序的生存周期。


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 摩托车半年没审怎么办 驾照扣分未缴款怎么办 驾驶证过期在外地怎么办 三年驾校过期了怎么办 车年检过期半年怎么办 驾照过期未年检怎么办 驾驶证时间过了怎么办 驾证年审逾期怎么办 驾照a2扣分了怎么办 叉车年检过期了怎么办 部队驾驶证过期了怎么办 车检过期5天怎么办 b2被注销了怎么办 小车逾期未审验怎么办 汽车逾期未审验怎么办 对方无偿还能力怎么办 摩托车驾驶证年审过期怎么办 当兵父亲有前科怎么办 被动态监控了怎么办 学习驾驶证明过期怎么办 a2驾驶证扣分了怎么办 c1驾驶证脱审怎么办 摩托车驾驶证脱审怎么办 行车证到期了怎么办 外省驾驶证掉了怎么办 错过教师证体检怎么办? c3驾驶证怎么办c1证 驾驶证扣分18分怎么办 货车罚款单上没写金额怎么办 报名费驾校不退怎么办 异地学车暂住证怎么办 考驾照老是紧张怎么办 驾照老考不过怎么办 三轮摩托车行驶证怎么办 a2驾驶证附件假背扣怎么办 驾驶证扣分15分怎么办 烟草证副本丢失怎么办 身份证异地丢了怎么办 营业执照正本遗失了怎么办 换新驾照过期了怎么办 武汉暂住证过期了怎么办