📄 lib0027.html
字号:
<span style="background-color:d9d9d9">_main ENDP</span>
<span style="background-color:d9d9d9">_TEXT ENDS</span>
<span style="background-color:d9d9d9">END</span>
</pre>
</div>
<p class="para">OK, let us look at each step as it occurs to understand what the compiler is doing. The first important thing that happens is the call to <span class="fixed">sigma ()</span>. The invoking function, <span class="fixed">main ()</span>, has to set up its portion of the activation record:</p>
<div class="informalexample">
<pre class="literallayout">
; 20 : retval = sigma(array,5);
push 5
push OFFSET FLAT:_array
call _sigma
</pre>
</div>
<p class="para">The invoking function pushes on the arguments. The <span class="fixed">CALL</span> instruction automatically pushes a return address onto the stack. What about the return value? As it turns out, the compiler is smart enough to realize that recursion does not exist and uses the <span class="fixed">EAX</span> register to pass a return value back to <span class="fixed">main ()</span>.</p>
<a name="321"></a><a name="IDX-143"></a>
<p class="para">Once execution has reached <span class="fixed">sigma ()</span>, the sigma function sets up the bottom part of the stack frame:</p>
<div class="informalexample">
<pre class="literallayout">
push ebp
mov ebp, esp
sub esp, 8
</pre>
</div>
<p class="para">The index variable <span class="fixed">i</span> requires 4 bytes and the integer variable <span class="fixed">sum</span> requires 4 bytes. This accounts for the 8 bytes of local storage allocated by the prologue of <span class="fixed">sigma ()</span>.</p>
<p class="para">The activation record produced in this example resembles the one detailed in <a class="internaljump" href="#ch03fig09">Figure 3.9</a>.</p>
<div class="figure">
<a name="322"></a><a name="ch03fig09"></a><span class="figuremediaobject"><img src="images/fig171_01.jpg" height="305" width="316" alt="" border="0"></span>
<br style="line-height: 1">
<span class="figure-title"><span class="figure-titlelabel">Figure 3.9</span></span>
</div>
<p class="para">Once <span class="fixed">sigma ()</span> has calculated its sum, it places the return value in <span class="fixed">EAX</span> and cleans out the local storage. The <span class="fixed">RET</span> instruction automatically pops the return address off the stack.</p>
<div class="informalexample">
<pre class="literallayout">
; 13 : return(sum);
mov ax, WORD PTR _sum$[ebp]
; 14 : }
mov esp, ebp
pop ebp
ret 0
</pre>
</div>
<p class="para">When <span class="fixed">main ()</span> has things back under its control, it cleans up the arguments placed on the stack and extracts the return value from <span class="fixed">EAX</span>:</p>
<div class="informalexample">
<pre class="literallayout">
call _sigma
add esp, 8<a name="323"></a><a name="IDX-144"></a>
and eax, 65535 ;0000ffffH
</pre>
</div>
<p class="last-para">You should be able to appreciate the amount of bookkeeping done by the compiler to compute the size of each activation record and the location of each element in them. These calculations are all performed at compile time while the source code is being processed. You should also keep in mind that some compilers have very intelligent optimizers that will take advantage of certain circumstances (for example, by doing sneaky things like using registers to return values).</p>
<a></a>
</div>
<div class="section">
<h4 class="sect4-title">Scope</h4>
<p class="first-para">The <i class="emphasis">scope</i> of a program element (a variable declaration, a function, etc.) determines both the visibility and, potentially, the life span of the element. When a program element is visible, it can be accessed and manipulated. The life span of a program element determines when the element is created and destroyed.</p>
<p class="para">The one caveat to this rule is for program elements that have their storage space allocated off the heap, dynamically, during execution. In this case, scope only defines the visibility of the program element. The element will exist until it is reclaimed, which may or may not be related to the scope of the element.</p>
<p class="para">To explore the meaning of scope, let us examine how scope rules apply to variables in the C programming language. Scope rules in C are implemented through the use of code blocks. A <i class="emphasis">block</i> of code is a region of source code that lies between a pair of brackets (i.e., between a "{" and a "}").A function definition is an example of a block of code.</p>
<div class="informalexample">
<pre class="literallayout">
void myfunction()
{
# block of code
return;
}
</pre>
</div>
<p class="para">In fact, functions are actually at the top of the block hierarchy in C. Functions may contain other blocks of code, as long as the blocks of code are not function definitions (which is to say that function definitions <i class="emphasis">cannot</i> be nested in C). For example, the following function definition contains a few sub-blocks:</p>
<div class="informalexample">
<pre class="literallayout">
void myfunction()
{
int i;
for(i=0;i<10;i++)
{<a name="324"></a><a name="IDX-145"></a>
if((i%2)==0)
{
printf("%d is even\n",i);
}
}
{
int j=10;
printf("j=%d\n",j);
}
return;
}
</pre>
</div>
<p class="para">From the previous function definition, we can see that blocks of code may be nested. In addition, although blocks of code are usually associated with program control statements, it is possible for blocks of code to exist independently of a program control statement. For example, the code that prints out the value of "<span class="fixed">j</span>" is a stand-alone block.</p>
<p class="para">Even though functions may contain other blocks of code, blocks of code (that are not function definitions) cannot independently exist outside of a function definition. For example, you would <i class="emphasis">never</i> see:</p>
<div class="informalexample">
<pre class="literallayout">
void myfunction1()
{
# block of code
return;
}
int i;
for(i=0;i<10;i++){ printf("%d\n",i); }
void myfunction2()
{
# block of code
return;
}
</pre>
</div>
<p class="para">An ANSI C compiler processing the previous code would protest that the <span class="fixed">for</span> loop does not belong to a function and would refuse to compile the code.</p>
<p class="para">The scope of variables in C is block based. A variable declared inside of a block of code is known as a <i class="emphasis">local variable.</i> A local variable is visible in the block in which it is declared and all the sub-blocks within that block. A variable cannot be accessed outside of the block in which it was declared. For example, the following snippet of C code is completely legal:</p>
<div class="informalexample">
<pre class="literallayout">
void main()
{<a name="325"></a><a name="IDX-146"></a>
int i;
for(i=0;i<10;i++)
{
int j=i*i;
printf("i=%d, i^2=%d\n",i,j);
}
return;
}
</pre>
</div>
<p class="para">The following snippet of C code, however, is <i class="emphasis">illegal</i>:</p>
<div class="informalexample">
<pre class="literallayout">
void main()
{
int i;
for(i=0;i<10;i++)
{
int j=i*i;
printf("i=%d, i^2=%d\n",i,j);
}
printf("i=%d, i^2=%d\n",i,j);
return;
}
</pre>
</div>
<p class="para">In the first case, we are perfectly within the syntactical rules of C when the variable "<span class="fixed">i</span>" is accessed in a sub-block. In the second case, however, if we try to access the variable "<span class="fixed">j</span>" outside of its declaring block, the compiler will emit an error. Naturally, there are two special cases to this rule: global variables and the formal parameters of a function.</p>
<p class="para">A <i class="emphasis">global variable</i> is a variable defined outside of any block of code. As such, a global variable is visible throughout a program by every section of code. Global variables also exist for the duration of a program's execution path.</p>
<p class="para">
<i class="emphasis">Formal parameters</i> are the variables specified in the prototype of a function. They are the variables that receive the arguments passed to a function when it is invoked. Formal parameters have visibility and a life span that is limited to the body of the function they belong to.</p>
<p class="para">Two basic techniques exist with regard to managing scope within the body of a procedure: the all-at-once approach and additional stack frames.</p>
<p class="para">One way to manage scope is to allocate storage for all of a function's local variables in the prologue code. In other words, we use the function's activation record to provide storage for every local variable defined inside of the function, regardless of where it is used. To support this approach, a compiler will use its symbol table to make sure that a local variable is not accessed outside of its declaring block.</p>
<a name="326"></a><a name="IDX-147"></a>
<p class="para">Here is an example to help illustrate this:</p>
<div class="informalexample">
<pre class="literallayout">
<span style="background-color:d9d9d9">/* --—localvars.c-—- */</span>
<span style="background-color:d9d9d9">void main(int argc, char *argv[])</span>
<span style="background-color:d9d9d9">{</span>
<span style="background-color:d9d9d9">unsigned char arr1[20];</span>
<span style="background-color:d9d9d9">unsigned long int i;</span>
<span style="background-color:d9d9d9">arr1[0]='a';</span>
<span style="background-color:d9d9d9">i=argc;</span>
<span style="background-color:d9d9d9">if(i<4)</span>
<span style="background-color:d9d9d9">{</span>
<span style="background-color:d9d9d9">unsigned char arr2[7];</span>
<span style="background-color:d9d9d9">unsigned long int j;</span>
<span style="background-color:d9d9d9">unsigned long int k;</span>
<span style="background-color:d9d9d9">arr2[0]='b';</span>
<span style="background-color:d9d9d9">j=5;</span>
<span style="background-color:d9d9d9">k=6;</span>
<span style="background-color:d9d9d9">}</span>
<span style="background-color:d9d9d9">else</span>
<span style="background-color:d9d9d9">{</span>
<span style="background-color:d9d9d9">unsigned char arr3[17];</span>
<span style="background-color:d9d9d9">arr3[0]='c';</span>
<span style="background-color:d9d9d9">}</span>
<span style="background-color:d9d9d9">}</span>
</pre>
</div>
<p class="para">By looking at its assembly code equivalent, we can see how storage for all these variables was allocated:</p>
<div class="informalexample">
<pre class="literallayout">
<span style="background-color:d9d9d9">.386P</span>
<span style="background-color:d9d9d9">.model FLAT</span>
<span style="background-color:d9d9d9">PUBLIC _main</span>
<span style="background-color:d9d9d9">_TEXT SEGMENT</span>
<span style="background-color:d9d9d9">_argc$ = 8</span>
<span style="background-color:d9d9d9">_arrl$ = -24</span>
<span style="background-color:d9d9d9">_i$ = -4</span>
<span style="background-color:d9d9d9">_arr2$31 = -40</span>
<span style="background-color:d9d9d9">_j$32 = -28</span>
<span style="background-color:d9d9d9">_k$33 = -32</span>
<span style="background-color:d9d9d9">_arr3$35 = -60</span>
<span style="background-color:d9d9d9">_main PROC NEAR</span>
<span style="background-color:d9d9d9">; Line 4</span>
<span style="background-color:d9d9d9">push ebp</span>
<span style="background-color:d9d9d9">mov ebp, esp</span>
<span style="background-color:d9d9d9">sub esp, 60 ; 0000003cH</span>
<span style="background-color:d9d9d9">; Line 8</span>
<span style="background-color:d9d9d9">mov BYTE PTR _arr1$[ebp], 97 ; 00000061H</span>
<span style="background-color:d9d9d9">; Line 9</span>
<span style="background-color:d9d9d9">mov eax, DWORD PTR _argc$[ebp]</span><a name="327"></a><a name="IDX-148"></a>
<span style="background-color:d9d9d9">mov DWORD PTR _i$[ebp], eax</span>
<span style="background-color:d9d9d9">; Line 11</span>
<span style="background-color:d9d9d9">cmp DWORD PTR _i$[ebp], 4</span>
<span style="background-color:d9d9d9">jae SHORT $L30</span>
<span style="background-color:d9d9d9">; Line 16</span>
<span style="background-color:d9d9d9">mov BYTE PTR _arr2$31[ebp], 98 ; 00000062H</span>
<span style="background-color:d9d9d9">; Line 17</span>
<span style="background-color:d9d9d9">mov DWORD PTR _j$32[ebp], 5</span>
<span style="background-color:d9d9d9">; Line 18</span>
<span style="background-color:d9d9d9">mov DWORD PTR _k$33[ebp], 6</span>
<span style="background-color:d9d9d9">; Line 20</span>
<span style="background-color:d9d9d9">jmp SHORT $L34</span>
<span style="background-color:d9d9d9">$L30:</span>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -