📄 6.3.1.htm
字号:
<html>
<head>
<title>编译原理</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<link type="text/css" rel="stylesheet" href="../css/specification.css">
</head>
<body>
<table align=right width=300>
<tr>
<td><img src="../images/previous.gif" onmouseover="javascript:style.cursor='hand'" onclick="vbscript:window.location.href='6.3.0.htm'"></td>
<td><img src="../images/next.gif" onmouseover="javascript:style.cursor='hand'" onclick="vbscript:window.location.href='6.3.2.htm'"></img></td>
</tr>
</table>
<br><br>
<font class="title2"><b>6.3.1 静态存储分配</b></font>
<table><tr><td>    </td>
<td class="content">
<P>
静态分配是在编译时刻为每个数据项目确定出在运行时刻的存储空间中的位置。换句话说,在静态分配中,在编译源程序的时候把名字联编于存储空间中。由于这些联编在运行时刻不再发生变化,一个过程无论在哪一次活动中,其中的名字每次均联编到同样的存储位置上。这种性质允许局部名字的值在过程的活动离开时被保留下来。即,当控制返回到一个过程时,该过程的局部名字的值与上次控制离开这个过程时的值是同样的。
</p>
</td></tr></table>
<table><tr><td>    </td>
<td class="content">
<P>
然而,仅使用静态分配策略有某些限制,主要包括下列几点:
</p>
</td></tr></table>
<table><tr><td>    </td>
<td class="content">
<p>
1.要求数据目标的大小和它们在内存位置上的约束须在编译时刻就知道;
</td></tr></table>
<table><tr><td>    </td>
<td class="content">
<p>
2.限制递归过程的使用;
</td></tr></table>
<table><tr><td>    </td>
<td class="content">
<p>
3.数据结构不能动态地来建立,因为没有运行时刻存储分配的机制。
</td></tr></table>
<table><tr><td>    </td>
<td class="content">
<p>
在适合以上要求的情况下,在编译时刻就可以确定出每个过程的活动记录的位置以及记录中每一个名字所占用的存储空间。从而就可以把数据在运行时刻的地址填入到目标代码之中,以使目标代码可以根据这些地址直接找到它所需要的数据。
</td></tr></table>
<table><tr><td>    </td>
<td class="content">
<p>
(1)PROGRAM CNSUME <br>
(2) CHARACTER * 50 BUF <br>
(3) INTEGER NEXT <br>
(4) CHARACTER C,PRDUCE <br>
(5) DATA NEXT/1/,BUF/ ''/ <br>
(6) C=PRDUCE()。
<br>
(7) BUF(NEXT:NEXT)=C
<br>
(8) NEXT=NEXT+1
<br>
(9) IF(C.NE.'
' 〕GOTO 6 <br>
(10) WRITE(*,'(A)')BUF
<br>
(11) END <br>
(12)CHARACTER FUNCTION PRDUCE() <br>
(13) CHARACTER * 80 BUFFBR <br>
(14) INTEGER NEXT <br>
(15) SAVE BUFFER,NEXT <br>
(16) DATA NEXT/81/ <br>
(17) IF(NEXT.GT.80)THEN
<br>
(18) READ(*,'(A)')BUFFER
<br>
(19) NEXT=1
<br>
(20) END IF <br>
(21) PRDUCB=BUFFER(NEXT:NEXT)
<br>
(22) NEXT=NEXT+1
<br>
(23) END </p>
<p> <br>
图6.8 一个Fortran 77程序 </p>
<p>
</td></tr></table>
<table><tr><td>    </td>
<td class="content">
<p>
Fortran的设计允许使用静态存储分配。我们知道,一个Fortran程序由一个主程序、若干子程序和函数(可以都称为过程)组成。见图6.8中的Fortran 77程序。使用图6.6中的内存组织,程序的代码和活动记录的设计如图6.9所示。在CNSUME的活动记录之中,有局部名字BUF,NEXT和C的空间。BUF对应的存储空间存放一个包含50个字符的串。其后跟有存放NEXT的整数值空间和存放C的字符值的空间。注意,NEXT在PRDUCE中又被说明这一事实是不成问题的,因为两个过程中的局部名字各自在它们自己的活动记录中占有空间。
</td></tr></table>
<table><tr><td>    </td>
<td class="content">
<p>
由于可执行的代码和活动记录的大小在编译时刻都是可知的,因此,使用不同于图6.9的内存组织也是可能的。譬如Fortran编译程序可以把过程的活动记录与这个过程的目标代码放在一起。
</td></tr></table>
<br>
<center><img src="6_9.gif" width="442" height="309"></center>
<br>
<table><tr><td>    </td>
<td class="content">
<p>
<b>例6.4</b> 图6.8中的Fortran程序依赖于通过过程活动保留下来的局部名字的值。Fortran 77中的一个SAVE语句指明:局部名字的值在一个活动的开始和上次活动结束时必须是相同的。这些局部名字的初始值可由一个DATA语句来说明。
</td></tr></table>
<table><tr><td>    </td>
<td class="content">
<p>
过程PRCUDE中第(18)行上的语句每次将正文的一行读入到缓冲区BUFFER中。这个过程的每次活动都传递相继的字符。主程序CNSUME也有一个缓冲区BUF,它用于收集字符直到出现一个空格为止。例如,对于输入
<BR> hello world
<BR>由过程PRDUCE的活动所返回的各个字符在图6.10中给出;程序的输出为
<BR> hello
<BR>用于存放PRDUCE读入的正文行的缓冲区BUFFER必须在两次活动之间保留着它的值。第(15)行的SAVE语句确保当控制再回到PRDUCE时,局部名字BUFFER和NEXT的值与上次控制离开PRDUCE时是一样的。第一次控制到达PRDUCE时,局部名字NEXT的值是从第(16)行的DATA语句中得到的。这样,NEXT被初始化为8l。
</td></tr></table>
<br>
<center><img src="6_10.gif" width="586" height="151"></center>
<p align=center>图6.10 由过程PRDUCE的活动所返回的各个字符</p>
<br>
<table align=right width=300>
<tr>
<td><img src="../images/previous.gif" onmouseover="javascript:style.cursor='hand'" onclick="vbscript:window.location.href='6.3.0.htm'"></img></td>
<td><img src="../images/next.gif" onmouseover="javascript:style.cursor='hand'" onclick="vbscript:window.location.href='6.3.2.htm'"></img></td>
</tr>
</table>
</BODY>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -