变量的声明与定义以及区别

ANSI C规定:变量必须先定义、后使用,因此当用C定义变量时,不仅需要指定变量名,而且还必须告诉编译器其存储的数据类型,变量类型告诉编译器应该在内存中为变量名分配多大的存储单元,用来存放相应变量的值(变量值),而变量仅仅是存储单元的别名,供变量使用的最小存储单元是字节(Byte)。

由此可见,每个变量都占据一个特定的位置,每个存储单元的位置都由“地址”唯一确定并引用,就像一条街道上的房子由它们的门牌号码标识一样。即从变量中取值就是通过变量名找到相应的存储地址,然后读取该存储单元中的值,而写一个变量就是将变量的值存放到与之相应的存储地址中去。

由于变量的定义不是可执行代码,因此要求局部变量的定义必须位于用“{}包围的程序块”的开头,即在可执行代码的前面。比如:

     int     LowerLimit = 80;                                       // 定义LowerLimit为整型变量

    即在定义LowerLimitint类型数据时,系统就已经为变量LowerLimit分配了存储单元。请注意区分变量名和变量值这两个不同的概念,其中,LowerLimit为变量名,80为变量LowerLimit的值,即存放在变量LowerLimit的存储单元中的数据。

那么到底如何获得变量的地址呢?C语言使用“&(地址运算符)加变量名”的方式获取变量的地址,比如,&LowerLimit就代表变量LowerLimit的地址,详见后续相关章节的描述。

一个定义只能指定一种变量类型,虽然后面所带的变量表可以包含一个或多个该类型的变量:

     int    LowerLimit , UpperLimit , sum;                                                            

但如果将一个定义语句中的多个变量拆开在多个定义语句中定义的话:

          int    LowerLimit;                                                                                       // LowerLimit为数据下限

      int    UppeLimit;                                            // UpperLimit为数据上限

      int    sum;                                                 //  sum为求和的结果

则可在各个定义语句中添加注释,则大大提高了程序的可阅读性,而且修改起来更加方便,但C编译器会忽略在每行右边用于描述变量用途的注释语句。与此同时还可以在定义中,对变量进行初始化,即允许在变量名的后面紧跟一个等号以及一个表达式。

int    LowerLimit = 1;

int   UpperLimit = LowerLimit+50;

     int   sum; 

       2.外部变量的声明

      由于变量LowerLimit是在别的文件中定义的,那么只要在引用之前用关键字extern对该变量作“外部变量声明”即可,无需再为变量LowerLimit分配存储单元,这种情况称之为声明或引用性声明。比如:

 extern   int     LowerLimit;                               // 将已定义的外部变量LowerLimit的作用域扩展到此

在这里将extern置于变量前,就是为了告诉编译器变量LowerLimit这个名字已经在别的文件中被定义了,因此遇到此变量时,需在其它模块中寻找与之相应的定义。 

有时程序是由多个源程序文件组成的,那么只需要在其中任一个文件中定义外部变量LowerLimit,而在另一个文件中用extern对变量LowerLimit作“外部变量声明”,即可将外部变量的作用域扩展到其它文件。

extern用于声明外部变量时,则类型名可写也可不写,由于声明变量不是定义变量,则可以不指定类型,只需写出变量名即可。比如:

extern    LowerLimit;                                                  

注意extern不仅可用于声明变量,而且还可以用于声明数组和指针,以及用于声明外部函数,详见后续相关章节的描述。

       3.静态变量的定义

当用static修饰变量时,则全局变量与局部变量都保存在内存的静态区。即便函数运行结束,而静态变量的值都不会被销毁,以后仍然还可以继续使用。

1)静态全局(外部)变量

       static用于定义外部变量时,则变量仅被所定义的文件使用,而其它文件则无法使用它。比如:

     static unsigned char      __GucTask0;                // 任务0测试变量

         使用静态全局变量的好处就是在进行模块化程序开发时,不用担心外部变量名的冲突,只需在每个文件中定义全局变量时加上static即可。

2)静态局部变量

静态局部变量则是在函数体内定义的,那么只能在这个函数中使用。

       注意static还可以用于修饰函数,如果在函数前加static,则该函数只能成为被本文件中的其它函数所调用的静态函数(内部函数),其好处就是不用担心函数名的冲突,便于模块化开发,

     4. 常变量的声明

为了提高程序的可阅读性与可维护性,ANSI C允许用户命名常量named constant,声明为const的变量)。

当它被初始化之后,它的值便不能改变,因此const主要用于声明其值不会修改的变量。

ANSI C规定:可以使用const关键字声明常量,修饰符const可以用在类型说明符前,也可以用在类型说明符后。比如:

int  const   MAX_LENGTH = 78;                   // 命名常变量的最佳方式是使用大写字母

const   int  MAX_LENGTH = 78;                    // MAX_LENGTH的初值为78

虽然const修饰MAX_LENGTH的值是常量,而实际上MAX_LENGTH却是一个读变量。编译器仅给出了与只

读变量MAX_LENGTH对应的内存地址,却并没有为只读变量MAX_LENGTH分配存储单元,而是将它们保存在符号表中,在编译时直接进行替换优化。因此使用const修饰常变量,可以节省空间,避免了不必要的内存分配,而且执行效率更高。  

 既然使用const也可以定义常量,那么它与符号常量到底有什么区别呢?

 由于const定义的常量有数据类型,因此编译器会对用const声明的只读变量进行类型校验,以减少出错的几率;虽然可以使用#define指令定义符号常量,但它在预编译进行字符替换之后,符号常量就不存在了,因为#define宏定义的立即数是没有类型的。很多开发环境只能调试const声明的常量,而不支持#define。由此可见,const#define声明常量更有优势。因此const的引入不仅消除预编译指令的缺点,而且继承了预编译指令的优点。

  虽然在很多时候const#define的优化,但有时#defineconst有优势,因为#define不仅声明常量,而且还可以声明“带宏的参数”,这是const无法做到的,所以说const相对于#define的优势仅限定在声明常量上。

    注意const除了可以修饰只读变量之外,还可以用于修饰数组、指针、函数的参数与函数的返回值,详见后续相关章节的描述。 

5. 标识符

ANSI C规定标识符只能由字母、数字和下划线3种字符组成,且第1个字符必须为字母或下划线。比如:

__GucTask0

注意C是区分大小写字母的语言,也就是说,由相同字母组成的字符,如果大小写不同,就会被看做不同的字符。比如,命名agesum的变量与AgeAGE以及Sum的变量就是不同的变量。一般来说,变量名常用小写字母来表示,比较符合人们的阅读习惯。

虽然ANSI C并没有规定标识符的长度,但各个编译器都有自己的规定,比如,Turbo C则允许变量名最多不超过32个字母。

    关键知识点:变量的声明与定义   

l         声明与定义的区别

    广义地说,声明包含定义,但并非所有的声明都是定义。对于“int lower_limit;”来说,它既是声明又是定义;而对“extern lower_limit;”来说,它是声明不是定义。

“声明”仅仅告诉编译器变量名的值的类型而已,不会生成目标代码,当然也不会给它分配存储空间,更不会增大可执行程序的体积。由于声明并不分配存储空间,因此同一个声明可以在程序中多次出现。它的位置可在执行代码之外,也可在执行代码里面。

而“定义”不仅要告诉编译器变量名的值的类型,而且还要给变量分配存储空间。既然在定义变量时就已经建立了存储空间,那么变量的定义只能出现一次,且它的位置在所有执行代码之外。

    由于系统是根据外部变量的“定义”来分配存储空间的,因此对外部变量的初始化只能在“定义”时进行,不能在“声明”中进行,而“声明”则是告诉编译器,该变量已经存在。 

l         变量与函数的多源文件共享

当希望在多个源文件中共享变量或函数时,需要确保定义与声明的一致性。最好的安排是在某个相关的“.c”文件中定义,然后在“.h”文件(头文件)中进行外部声明,在需要使用的时候,只要包含对应的头文件即可。定义变量的“.c”文件也应该包含该头文件,以便编译检查定义和声明的一致性    

变量的声明有两种情况:

1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。

2、另一种是不需要建立存储空间的。 例如:extern int a 其中变量a是在别的文件中定义的。

前者是“定义性声明(defining declaration)”或者称为“定义(definition)”,而后者是“引用性声明(referncing declaration)”,从广义的角度来讲声明中包含着定义,即定义是声明的一个特例,所以并非所有的声明都是定义,例如:int a 它既是声明,同时又是定义。然而对于 extern a 来讲它只是声明不是定义。一般的情况下我们常常这样叙述,把建立空间的声明称之为“定义”,而把不需要建立存储空间的声明称之为“声明”。很明显我们在这里指的声明是范围比较窄的,即狭义上的声明,也就是说非定义性质的声明,例如:在主函数中:

int main() {
extern int A;
//这是个声明而不是定义,声明A是一个已经定义了的外部变量
//注意:声明外部变量时可以把变量类型去掉如:extern A;
dosth(); //执行函数
}
int A; //是定义,定义了A为整型的外部变量

外部变量的“定义”与外部变量的“声明”是不相同的,外部变量的定义只能有一次,它的位置是在所有函数之外,而同一个文件中的外部变量声明可以是多次的,它可以在函数之内(哪个函数要用就在那个函数中声明)也可以在函数之外(在外部变量的定义点之前)。系统会根据外部变量的定义(而不是根据外部变量的声明)分配存储空间的。对于外部变量来讲,初始化只能是在“定义”中进行,而不是在“声明”中。所谓的“声明”,其作用,是声明该变量是一个已在后面定义过的外部变量,仅仅是为了“提前”引用该变量而作的“声明”而已。extern 只作声明,不作任何定义。

(我们声明的最终目的是为了提前使用,即在定义之前使用,如果不需要提前使用就没有单独声明的必要,变量是如此,函数也是如此,所以声明不会分配存储空间,只有定义时才会分配存储空间。)

用static来声明一个变量的作用有二:

(1)对于局部变量用static声明,则是为该变量分配的空间在整个程序的执行期内都始终存在。

(2)外部变量用static来声明,则该变量的作用只限于本文件模块。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值