变量和内存分配

无论用什么语言编制的程序,都是为让计算机完成某一特定功能而编写的文本文件。这些文本文件是不能直接在机器上运行的,它们必须经过系统软件(包括编辑器和编译器)的输入并编译或汇编后,转换成二进制的可执行代码,才是计算机可以识别的机器语言。此时,程序就是一个包含二进制可执行代码文件的模块。当内核把二进制的可执行代码装入内存后,它由三部分组成:代码段、数据段、堆栈段。在线性地址的低地址字段是代码段,存放程序经编译后的可执行代码(程序文本)。在操作系统中,代码段是只读的,不能修改,所以,代码段的长度是不会改变的。在程序文本(代码段)的上方是数据段,用来存放程序的变量、字符串和其它数据。它分为初始化静态数据(data)和未初始化静态数据(BSS)。数据段的长度是可以改变的。程序可以修改其中的变量。在程序设计中,将其值可以改变的量称为变量。每一个变量在内存中都要占据一定的存储单元,因此,每一个变量也就会具有一定的存储属性

从变量的作用域(空间)的角度来考虑变量的属性,可将变量分为全局变量和局部变量。

局部变量

局部变量是指在一个函数内部定义的变量,它只中本函数范围内有效。

说明:

1、在主函数中定义的变量只在主函数中有效,且主函数也不能使用其他函数中定义的变量

2、在不同函数中可以使用相同名字的变量,它们代表不同的变量,互不干扰;

3、形参也是局部变量,也只在对应的函数中有效,其他函数不能使用

4、在一函数内部,可在复合语句(有一个{}括起的一组语句)中定义变量,这些变量只在本复合语句中有效。

全局变量

程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数之外定义的变量称为外部变量(extern),也叫全局变量。全局变量的有效范围是从定义变量的位置开始到本源程序文件结束为止,其关键字extern可以省略。

说明:

1、在一个函数中既可以使用本函数中的局部变量,又可以使用有效的全局变量。

2、设置全局变量的作用是增加函数间数据联系的渠道。由于同一文件中的若干函数均能引用全局变量的值,因而若在一个函数中改变了全局变量的值,就能影响其他函数,相当于各函数有了直接的传递通道,即公共变量,从而可能从函数获得一个以上的返回值。

3、建议不在必要时不要使用全局变量,因为:

(1)全局变量在程序的整个执行过程中都占用存储单元;

(2)它将降低函数的通用性。因为函数执行时要依赖对应的全局变量

(3)降低了函数的独立性,从而降低了函数的内聚度,增加了函数间的耦合度。而结构化程序设计的基本原则是:应争取组成程序的各模块(在C语言中用函数实现)具有尽可能高的内聚度和尽可能低的耦合度。

(4)如果外部(全局变量)在文件开头定义,则其作用范围为整个文件;如果不在文件开头定义,则其作用范围为定义点到文件终了处。若在定义点前的函数想引用此外部变量,则应在该函数中用关键字extern对外部变量作说明

(5)如果在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量不起作用

 

从变量存在的时间(生存期)的角度来考虑变量的属性,则可将变量分为动态存储变量和静态存储变量。在C语言中,每一个变量和函数都具有两个属性:类型和存储类别。类型即int、float等,存储类别指的是数据在内存中存储的方式(属性)。存储方式分为静态存储和动态存储两大类,但具体有四种:自动型(auto,即局部变量)、寄存器型(register)、静态型(static)、外部型(extern,其它文件中定义过的全局变量),其中,静态型和外部型变量为静态存储变量,自动型和寄存器型变量为动态存储变量。在定义变量时,应先说明存储类型,再说明数据类型,最后说明变量名。

因此,静态存储变量也分静态全局变量和静态局部变量,动态存储变量则都是局部的?静态存储变量是指在程序运行期间占据固定的内存单元的变量,包含全局(extern,当然extern可省)变量、静态全局变量(加static的全局变量)和局部静态变量(冠以关键字static的局部变量)。

1、对于全局变量,在程序开始执行时就给它分配内存单元,直到程序终结时才释放。它可由本文件和其它文件中的函数所引用。在其它文件中被引用时,应该在文件开头有一个extern说明(注意,此说明在函数外),说明在引用该变量的文件中出现的变量是一个已在其他文件中定义过的全局(外部)变量,本文件不必再为它分配内存单元。本来外部变量的作用域是从它的定义点到文件结束,但可以用extern说明将其作用域扩大到有extern说明的其它文件。但使用这样的全局变量是应十分慎重,因为在执行一个文件中的函数时,可能会改变该全局变量的值,从而会影响到另一文件中函数的执行结果。

2、对于静态外部(全局)变量,即冠以static的全局变量,也在编译时分配在静态存储区,它只在本文件内有效,其它文件不能引用。(编译还是执行?)

3、对于局部静态变量,即在局部变量前冠以关键字static的变量,在编译到它时分配存储单元,直到程序结束才释放。在程序的执行过程中它们占据固定的存储单元,而不是动态的分配和释放。当希望函数中的局部变量之值在函数调用结束后不消失而保留原值时,可定义为静态局部变量。这样,函数调用结束后,其占用的单元不释放,在下一次调用该函数时,变量保留上一次函数调用结束时的值。静态局部变量不能被其它函数访问。

注:当全局变量和静态局部变量未赋初值时,系统自动置为0。

动态存储变量

存储在动态存储区的变量叫动态存储变量。它们在程序执行的某一时刻被动态地建立并在另一时刻又被动态地撤消,即使用到时为其分配存储单元,使用完即释放。

在动态存储区存储的变量有:

1、函数的形参变量。在调用函数时给形参变量分配存储空间。

2、局部变量(未加static说明的局部变量,即自动变量auto)。自动变量是在函数或复合语句内部定义的变量(即前面所说的局部变量)。当程序块执行时,为它定义的自动型变量分配内存单元,在程序执行完成后,便释放这些变量占用的内存单元。在定义自动型变量时,一般缺省存储类型名auto;自动变量若未赋初值,则其初值不定(将分配给它的存储单元的当前值作为初值,这是和静态存储变量不同的地方)

3、函数调用时的现场保护和返回地址等。

以上三种变量在函数调用开始时分配动态存储单元,函数结束时释放这些单元。在程序执行过程中,这种分配和释放是动态的,如果一个程序中多次调用同一函数,分配给此函数中局部变量的存储空间地址可能是不同的。如果一个程序包含若干个函数,每个函数中的局部变量的生存期并不等于整个程序的执行周期,而只是程序执行周期的一部分,并根据函数调用的需要,动态地分配存储空间。

寄存器变量

一般情况下,变量(包括静态存储方式和动态存储方式)的值都是存放在内存中的,当程序中用到哪一个变量的值时,同控制器发出指令将内存中该变量的值送到运算器中。经过运算器进行运算。如果需要存数,再从运算器将数据送到内存存放。 但如果有一些变量使用频繁,为了节省存取时间,提高执行效率,C语言允许将其值存放在运算器中的寄存器中,需要时直接从寄存器中取出参加运算,不必再到内存中去存取,这种变量叫做“寄存器变量”,用关键字register于以说明,在函数内部定义

说明 :

1、只有局部自动变量和形式参数可以作为寄存器变量,其他(如全局变量)不行。在调用一个函数时占用一些寄存器以存放寄存器变量的值,调用结束时释放寄存器。

2、一个计算机系统中的寄存器数目是有限的,不能定义任意多个寄存器变量,且不同的系统允许使用的寄存器变量个数不同。

3、不同系统对寄存器变量的处理是不同的。微机上用的MS C,Turbo C将寄存器变量当作自动变量处理,分配内存单元,并不真正把它们存放在寄存器中。因此,虽然程序合法,但并不提高执行速度。而PDP-11只允许将int、char和指针型变量定义为寄存器变量

4、局部静态变量不能定义为寄存器变量。即不能把变量既放在静态存储区中,又放在寄存器中。

总结:

全局变量、静态数据、常量存放在全局数据区(即我上面所说数据段),所有函数的代码存放在代码区,为运行函数而分配的局部变量、函数参数、返回数据、返回地址等存放在栈区。  

  所以在同一个进程里,多个任务(线程)的全局变量和静态变量都应该是共享同一块内存(全局数据区即数据段)  

  而在不同的进程里,重新加载了代码,各个进程间的全局变量和静态变量当然不是拥有同一块内存。 

  在psos下,各个任务是不同的线程,所以各个任务的全局变量和静态变量是在同一块内存。而我的另一个程序中(在sco   unix),是每次运行都是一个新的进程,所以各个进程的全局变量和静态变量拥有不同的内存 

                                                 变量分类表

 

 

在计算机中存储的位置

作用域

生存期

引用情况

本函数内

函数外

本函数内

函数外

本文件内

文件外

自动(局部)变量

内存动态存储区

(即栈区)

有效

无效

有效

无效

无效

无效

静态局部变量

内存静态存储区

(即数据段)

有效

无效

有效

有效

无效

无效

寄存器变量

CPU中的寄存器

有效

无效

有效

无效

无效

无效

静态全局(外部)变量

内存静态存储区

(即数据段)

有效

有效

有效

有效

有效

无效

非静态全局(外部)变量

内存静态存储区

(即数据段)

有效

有效

有效

有效

有效

可引用

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

堆和栈

堆和栈是两个概念。堆栈是一个很混淆的说法。栈是局部变量与参数存放的空间,是由编译器来处理的。 堆是动态分配空间,需要自已管理,申请或释放。 “栈”是“堆栈”的简称,英文为stack,是个先进后出的线性结构,主要用来存放auto类型的局部变量、给函数传递参数等。至于“堆”,英文名为heap,主要用作动态分配内存用,new分配的内存是在堆中而不是在栈中!堆和栈   都是存储空间的分派方式,存储空间的分配方式有3种,静态存储分配,栈式分配,和堆式分配;后两者属于动态内存的分配。   
  静态存储分配要求在编译时能够知道所有的变量的存储的要求,比如程序种的变量和常量;栈式存储则要求在过程中的入口处必须知道所有的存储要求。前两种存储空间的分配方式比较常见,有时候都不能满足上面两种情况的情况,有些存储的要求只能在程序执行的过程中被赋新值或创建新的结构事例才能知道,这些语句有new()   dispose   ,allocate   free   等,对于这种情况,采用了堆的存储空间分配管理。 堆,是一块固定大小的空间,当需要分配的时候,就在这些空间里,划分出一块给用户用,当用完了,就可以释放掉,他没有后进先出的规则。就像仓库里的东西,随时可以拿出来,随时可以方回去。   堆的操作时编译器的工作,用户不去管理它。在编译原理中有关于堆和栈的详细介绍 。  

在汇编中,其实就没有堆的概念,只有数据段和栈,即data segment和stack。汇编中,已经基本上把堆栈的概念当作栈了。对栈的操作,用户使用,也可以对自己的栈进行管理。堆,由于比较麻烦,堆的管理已经不是用户的职能之内了,体现在用户的面前的,只是存储空间的动态申请和释放。如果非要弄清楚汇编里堆是如何实现的,倒不如看看汇编里是如何动态的管理存储空间的。汇编里实现存储空间的动态管理,采用的是两个中断:   21号中断中的   48H和   49H   两个功能   
  这两功能具体使用方法,呵呵,查查中断手册就知道了。   
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值