外部变量和外部函数

C程序由一组对象组成,这些对象包括程序中所使用的变量和实现特定功能的函数。变量可以分为函数内部定义、使用的变量和函数外部定义的变量,通常情况下,把函数内部定义、使用的变量称为内部变量或局部变量,而将在函数外部定义的、供许多函数所使用的变量称为外部变量,一般情况下,也可以称为全局变量。

  由于C语言不允许在一个函数中定义其他函数,因此函数本身是外部的。一般情况下,也可以说函数是全局函数。在缺省情况下,外部变量与函数具有如下性质:所有通过名字对外部变量与函数的引用(即使这种引用来自独立编译的函数)都是引用的同一对象(标准中把这一性质称为外部连接)。

  由于外部变量是可以全局访问的,这就为在函数之间交换数据提供了一种可以替代函数变元欲返回值的方法。任何函数都可以用名字来访问外部变量,只要这个名字已在某个地方做了说明或定义。如果要在函数之间共享大量的变量,那么使用外部变量要比使用一个长长的变元表更方便、有效。然而,也可能导致程序在各个函数之间产生太多的数据联系。

  外部变量的用途还表现在它们比内部变量有更大的作用域和更长的生存期。内部自动变量只能在函数内部使用,当其所在函数被调用时开始存在,当函数退出时消失。而外部变量是永久存在的,他们的值在从一次函数调用到下一次函数调用之间保持不变。因此,如果两个函数必须共享某些数据,而这两个函数都互不调用对方,那么最为方便的是,把这些共享数据作为外部变量,而不是作为变元来传递。

1、外部变量的定义和使用

  根据C语言标准,在程序的所有源文件中,外部变量只能被定义一次,否则会导致重复定义的编译错误。

1.1 外部变量的定义与声明

  变量声明用于通报变量的性质(主要是变量的类型),而变量定义则除此之外还引起存储分配。如果在函数的外部包含如下说明:
  1. int    VarDesc;
  2. char          Array[MAXVAL];
复制代码
那么这两个说明定义了外部变量VarDesc与Array,并为之分配存储单元,同时也用作供源文件其余部分使用的说明。另一方面,如下两行:
  1. extern  int    VarDesc;
  2. extern  char          Array[];
复制代码
为源文件剩余部分声明了VarDesc是一个int 类型的外部变量,Array是一个char数组类型的外部变量(数组大小在其他地方确定),但这两个声明并没有建立变量或为它们分配存储单元,其中关键字extern表明该外部变量在其他地方被定义。

  根据C语言标准,外部变量虽然只能在某个文件中定义一次,但其作用域则是从其声明处开始一直到其所在的被编译的文件的末尾。因此其他文件可以通过extern说明来访问它。

1.2 外部变量的使用方式

  如果外部变量被不同的函数所引用,并且这些函数没有集中在一个源文件中,而是分布在不同的源文件中,那么函数在引用这些外部变量时,必须采取先声明再使用的方式,否则,在编译时会导致重复定义的编译错误。

  若在多个文件的多个函数中引用外部变量,就需要在这些函数中重复声明外部变量。这种方式可以解决编译问题,但是代码不够简洁。因此,在实际的编程中,大都采取了将外部变量统一定义在一个C源文件中,这个C源文件一般被称为global.c,然后在对应的头文件中,一般为global.h,声明外部变量,最后在需要引用外部变量的源文件中使用#include "global.h"的方式,函数就可以引用所有的外部变量。因此,一般情况下,global.c内容为:
  1. #include "global.h"       

  2. /* for example, define two vars */
  3. int    VarDesc;
  4. char          Array[MAXVAL];
  5. /* other external var define */
复制代码
在对应的global.h头文件的内容则为:
  1. #ifndef _GLOBAL_H   /* please insure _GLOBAL_H unique */
  2. #define _GLOBAL_H   /* avoid quotation iterativly */

  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif   /*__cplusplus */

  6. /* for example, declare two vars */
  7. extern  int    VarDesc;
  8. extern  char          Array[];

  9. /* other external vars declaration */

  10. #ifdef __cplusplus
  11. }
  12. #endif  /* __cplusplus */

  13. #endif        /* _GLOBAL_H */
复制代码
此外,在实际的编程中,这两个文件头部还应当有公司copyright声明、文件功能说明、版本说明、创建、修改历史等。

2、函数的定义和使用

  根据C语言标准,函数只能被定义一次,而且在函数中,不能再定义函数,因此函数本身是外部的。

2.1 函数的定义与声明

  定义函数是给出函数体的函数描述。一个函数只有在声明之后才能被引用。函数声明中,需给出函数名、返回类型、参数列表等。

  函数的作用域从其声明处开始一直到其所在的被编译的文件的末尾,如果一个函数在定义之前就要使用到,或者这个函数定义在与所要使用它的源文件不相同的源文件中,那么就需要在使用该函数前,使用关键字extern声明该函数,但由于函数默认是external的,因此函数声明前的extern可以省略,这也是标准库函数的头文件中,函数声明前没有extern的原因,但在实际的编程中,一般不推荐这样做,应当在函数声明前加上extern。

2.2 函数的组织和使用

  如果某个函数需要引用另一个函数,则需要在引用该函数前声明被引用的函数,否则可能会导致函数未定义错误。

  为了避免被引用函数的重复声明和方便函数的引用,在实际的编程之中,采用在对应的头文件中,统一声明函数的方式。需要引用某一个函数时,只需要在该函数的定义源文件中包含被引用函数的头文件即可。

  在实际的编程中,在头文件中声明函数,即声明函数原型,在对应的C源文件中,定义函数及其实现代码。因此,函数说明的头文件内容和格式为:
  1. #ifndef _FUNCNAME_H   /* please insure _ FUNCNAME _H unique */
  2. #define _ FUNCNAME _H   /* avoid quotation iterativly */

  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif   /*__cplusplus */

  6. /* for example, declare functions */
  7. extern  int    func (int, int, int);
  8. /* of course, maybe declare functions like below
  9. * int    func (int, int, int);
  10. */
  11. /* other functions declaration */

  12. #ifdef __cplusplus
  13. }
  14. #endif  /* __cplusplus */

  15. #endif        /* _ FUNCNAME _H */
复制代码
而在对应的C源文件内容为:
  1. #include " funcname.h"

  2. /* for example, define two vars */
  3. int    func (int a, int b, int c)
  4. {
  5.                 // functions body
  6. }

  7. /* other functions define */
复制代码
在实际的函数头文件和定义文件中还应当包含相应的头文件等,以及公司copyright声明、文件功能说明、版本说明、创建、修改历史等。对于具体的函数,还应当有函数说明、输入参数说明、返回说明、例外等。

3、静态外部变量和函数

  如果某外部变量和函数仅供它们各自所在的源文件中的函数使用,而不能被其他函数访问,那么就必须使用static关键字定义外部变量和函数。static说明适用于外部变量与函数,用于把这些对象的作用域限定为被编译源文件的剩余部分。通过外部static对象,可以把一些外部变量和函数隐藏在某个源文件中,使得这些外部变量和函数仅仅可以被该源文件使用和共享,但不能被该源文件之外的函数所引用。

  另外,static说明也可以用于说明内部变量。内部静态变量就像自动变量一样局部于某一个特定函数,只能在该函数中使用,但与自动变量不同的是,不管其所作函数是否被调用,它都是一直存在的,而不像自动变量那样,随着所在函数的调用与退出而存在与消失。换而言之,内部静态变量是一种只能在某一特定函数中使用的但一直占据存储空间的变量。

  一般情况下,为保证静态外部变量和函数能够被本源文件的函数所引用,需要在该源文件的所有函数之前定义静态外部变量和函数。那么,该C源文件的内容为:
  1. #include “funcname.h”       

  2. /* for example, define one static external var and one static function */
  3. static   int VarName = 0;
  4. static   int function (int a)
  5. {
  6.                 // function body
  7. }
  8. /* other static vars and functions */

  9. /* for example, define one function */
  10. char          func (char*, char)
  11. {               
  12.                 VarName = 5;
  13.                 function (VarName);
  14.                 // other function body
  15. }

  16. /* other functions define */
复制代码




外部变量,变量定义在其他文件中全局变量
extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。


C语言外部变量的使用以及extern的用法

C语言的外部变量的定义和引用对初学者来说,是个难点.

对外部变量的说明和定义不是一回事.对外部变量的说明,只是声明该变量是在外部定义过的一个全局变量..在这里引用.而对外部变量的定义,则是要分配存储单元.一个全局变量只能定义一次,却可以多次引用.

用extern声明外部变量,目的是可以在其它的文件中调用.具体使用见下面的例子:

                file1.c                                                       file2.c

        int i,j;//定义全局变量                                extern   int i,j;//外部变量说明

        char c;                                                        extern char c;

       void func()                                                    void func1()

     {                                                                     {

         }                                                                    }

在file2.c中对外部变量i,j,c进行了说明,就可以直接调用file1.c中定义的全局变量了

静态变量static的使用

有时在中断程序中定义了变量,不希望每次进入中断程序,变量就被赋初值.这时就要使用static变量.静态局部变量在编译时赋初值,既只赋初值一次.见下例:

void serial_interrupt() interrupt 4 using 3

{ static uchar i="0";

   i++;

}

上例中,编译时,i被赋初值0,以后每进入一次中断,i+1,而不是每次进入中断,i都被请零,再加1

如果在a.c中要调用在b.c中定义的函数func(),需要在a.c中声明该函数,表示该函数在别的源文件中定义。函数是可以互相调用的,因此函数都具有外部存储种类的属性。原则上调用一个在在本程序模块文件以外的其他模块文件所定义的函数,必须用关键字extern说明被调用函数是一个外部函数。实际使用中可以省掉extern。即下面两个函数声明没有明显的区别:

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

例如;

#include "2.h"
extern int a;
int _tmain(int argc, _TCHAR* argv[])
{
 test();
 printf("%d\n",a);
 
 return 0;
}

 

#include "2.h"
 int a;
int test()
{
 a=10;
 return 0;
}

//结果a=10;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/254741.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gulp中使用babel-polyfill编译es6拓展语法

今天想在新项目中使用es6的generators,发现虽然gulp已经有了babel编译,但仍会报错,网上查找后发现解决办法是加载polyfill,但是找到的办法都不试用我的项目。 解决办法:在index.html中加载node_modules的babel-polyfil…

CoDeSys

CoDeSys是全球最著名的PLC内核软件研发厂家德国的3S(SMART,SOFTWARE,SOLUTIONS)公司出的一款与制造商无关的IEC 61131-1编程软件。CoDeSys 支持完整版本的IEC61131标准的编程环境,支持标准的六…

使用halcon结合机械XY轴对相机进行9点标定

小哥哥小姐姐觉得有用点个赞呗! 先在halcon中计算仿射变换矩阵并验证 //在图像中找到的模板中心位置 PicX:[1680.721,2065.147,911.499,526.798,1290.920,1285.731,1300.953] PicY:[968.321,964.366,976.283,980.035, 587.055,394.727,1355.487] //与图像中查找…

Ubuntu Linux 提出新的发布模式——测试周

2019独角兽企业重金招聘Python工程师标准>>> 导读开源技术项目最大的优势之一就是社区的每个人都可以自由地提出想法,如果获得社区支持,它可以变成现实。著名的 Ubuntu 开发人员 Simon Quigley 就提出了一个可能改变 Ubuntu Linux 开发过程的…

264 I和IDR

I和IDR帧都是使用帧内预测的。它们都是同一个东西而已,在编码和解码中为了方便,要首个I帧和其他I帧区别开,所以才把第一个首个I帧叫IDR,这样就方便控制编码和解码流程。IDR帧的作用是立刻刷新,使错误不致传播,从IDR帧开始,重新算一个新的序列…

gen_caltab生成标定文件

目录gen_caltab(算子)描述参数gen_caltab(算子) gen_caltab - 为具有矩形排列标记的校准板生成校准板描述文件和相应的PostScript文件。 gen_caltab(:: XNum,YNum,MarkDist,Diamet…

主席树,喵~

稍微总结一下主席树吧 Too Difficult!搞了一天搞出一大堆怎么令人悲伤的辣鸡代码。总之先总结一下吧,以后碰到这种问题直接拿去毒害队友好了。 UPD 5/24 苟狗是沙比 一个节点记录三个信息:lson,rson,sum 用pid表示节点个数。 build void buil…

【转】小白级的CocoaPods安装和使用教程

原文网址:http://www.jianshu.com/p/e2f65848dddc 百度有很多CocoaPods的安装教程.第一次看的时候,确实有点摸不透的感觉.经过思考,一步一步来实践,前后花了三十几分钟,才顺利使用..所以想了想,我还是写一个小白级的教程吧.细到每一个细节都说明. 让你不用10分钟解决…

常见错误总结

少打头文件 少打using namespace std; 命名冲突&#xff0c;全局变量与局部变量命名一致&#xff0c;导致使用的值不是期望值 边读边写&#xff0c;导致改后读&#xff0c;覆盖写入的值 长整数移位溢出&#xff0c;1<<63是错误的&#xff0c;应该写成1ll<<63 循环变…

x264_sps_init

x264_sps_init此函数为序列量化集的初始化。主要对结构体x264_sps_t中参数的初始化。 void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) { sps->i_id i_id;首先设置序列参数集的ID b_qpprime_y_zero_transform_bypass判断码率控制方法是否是恒定质量…

HALCON相机标定相机内参相机外参

目录相机标定1.相机标定是什么2.怎么使用halcon进行相机内外参标定&#xff1f;&#xff08;1&#xff09;搭建硬件1.**相机连好电脑&#xff0c;用相机厂家软件打开相机&#xff0c;检查一下相机是否正常。**2.**接下来使用halcon连接相机**&#xff08;2&#xff09;开始标定…

ionic更改端口号

ionic serve -p 8888 —— 重新指定端口号为8888 serve [options] ............................... 启动本地服务器进行开发测试 dev/testing   [--consolelogs|-c] ..................... 输入app的控制台到ionic的控制台显示   [--serverlogs|-s] .....................…

angular change the url , prevent reloading

http://stackoverflow.com/questions/14974271/can-you-change-a-path-without-reloading-the-controller-in-angularjs $location.search({vln: $scope.vln_id}, false);会改变url中 &#xff1f; 后面的 搜索参数&#xff0c;但是controller不会重新实例化。angular 官方文档…

Ubuntu apt-get 更新/查看软件

ubuntu 升级软件&#xff1a; sudo apt-get update 更新源  sudo apt-get upgrade 更新已安装的包  sudo apt-get dist-upgrade 升级系统 ubuntu升级特定软件&#xff1a; 可以用 sudo apt-get install pkgname 看软件安装位置:dpkg -L xxxx 查看软件是否安装&#xff1…

X264设定

--aq-mode <integer> AQ method [1]- 0: Disabled- 1: Variance AQ (complexity mask)说明&#xff1a;自适应量化方法&#xff0c;可以改善某些场景过于模糊等问题&#xff0c;默认开启- 0: 关闭- 1: 可变AQ推荐值&#xff1a;默认范例&#xff1a;--aq-mode 1--aq-stre…

C#圆形卡尺测量程序基于halcon

废话不多说上源码 觉得帖子有用给点个赞哈 先来个效果图 下边的是源码&#xff0c;自己新建一个文件粘贴进去&#xff0c;包含到您现在的项目 中。这串源码后边是使用方法。 using System; using System.Collections.Generic; using System.Linq; using System.Text; usin…

MySQL松散索引扫描与紧凑索引扫描

什么是松散索引&#xff1f; 答&#xff1a;实际上就是当MySQL 完全利用索引扫描来实现GROUP BY 的时候&#xff0c;并不需要扫描所有满足条件的索引键即可完成操作得出结果。 要利用到松散索引扫描实现GROUP BY&#xff0c;需要至少满足以下几个条件&#xff1a;◆ GROUP BY 条…

算法马拉松24

算法马拉松24 A 小C的多边形 题意&#xff1a;n1个点的多边形。给外圈的边标记上1~n&#xff0c;里圈的边也标记上1~n&#xff0c;使得对于一个外圈相邻点与中间点构成的三角形的边权之和都相等。\(n \le 10^6\) 题解&#xff1a;显然每个三角形权值和为\(\frac{3(n1)}{2}\) 一…