編譯器設計-RunTime運行時環境

編譯器設計-RunTime運行時環境

Compiler Design - Run-Time Environment

作爲源代碼的程序僅僅是文本(代碼、語句等)的集合,要使其活動,它需要在目標計算機上執行操作。程序需要內存資源來執行指令。程序包含程序名、標識符等,運行時需要與實際內存位置進行映射。

所謂運行時,我們指的是正在執行的程序。運行時環境是目標機器的一種狀態,它可以包括軟件庫、環境變量等,爲系統中運行的進程提供服務。

運行時支持系統是一個包,主要由可執行程序本身生成,有助於進程與運行時環境之間的進程通信。它在執行程序時負責內存分配和取消分配。

激活樹Activation Trees

程序是一系列指令組合成若干過程的序列。過程中的指令是按順序執行的。過程有一個開始和結束分隔符,其中的所有內容都稱爲過程的主體。過程標識符及其內部的有限指令序列構成了過程的主體。

過程的執行稱爲其激活。激活記錄包含調用過程所需的所有必要信息。激活記錄可以包含以下單元(取決於使用的源語言)。
在這裏插入圖片描述
每當執行一個過程時,它的激活記錄都存儲在堆棧上,也稱爲控制堆棧。當一個過程調用另一個過程時,調用方的執行將被掛起,直到被調用的過程完成執行爲止。此時,被調用過程的激活記錄存儲在堆棧上。

我們假設程序控制按順序執行,當一個過程被調用時,它的控制權被轉移到被調用的過程。當被調用的過程被執行時,它將控件返回給調用方。這種類型的控制流使以樹(稱爲激活樹)的形式表示一系列激活變得更容易。

爲了理解這個概念,我們以一段代碼爲例:

. . .

printf(“Enter Your Name: “);

scanf(“%s”, username);

show_data(username);

printf(“Press any key to continue…”);

. . .

int show_data(char *user)

{

printf(“Your name is %s”, username);

return 0;

}

. . .

下面是給定代碼的激活樹。
在這裏插入圖片描述
現在我們知道過程是以深度優先的方式執行的,因此堆棧分配是過程激活的最佳存儲形式。
存儲分配Storage Allocation

運行時環境管理以下實體的運行時內存需求:

代碼:它被稱爲程序的文本部分,在運行時不會更改。它的內存需求在編譯時是已知的。
過程:它們的文本部分是靜態的,但它們是以隨機的方式調用的。這就是爲什麼堆棧存儲用於管理過程調用和激活。

變量:變量只有在運行時才知道,除非它們是全局變量或常量。堆內存分配方案用於管理運行時變量的內存分配和取消分配。

靜態分配Static Allocation

在這種分配方案中,編譯數據被綁定到內存中的一個固定位置,並且在程序執行時不會改變。由於預先知道內存需求和存儲位置,因此不需要內存分配和取消分配的運行時支持包。

堆棧分配Stack Allocation

過程調用及其激活通過堆棧內存分配進行管理。它適用於後進先出(LIFO)方法,這種分配策略對於遞歸過程調用非常有用。

Heap Allocation

僅在運行時才分配和取消分配過程本地的變量。堆分配用於動態地將內存分配給變量,並在不再需要變量時將其收回。

除了靜態分配的內存區域外,堆棧和堆內存都可以動態和意外地增長和收縮。因此,不能在系統中爲它們提供固定數量的內存。
在這裏插入圖片描述
如上圖所示,代碼的文本部分被分配了固定數量的內存。堆棧和堆內存被安排在分配給程序的總內存的最末端。兩個人都在互相殘殺和成長。

參數傳遞Parameter Passing

過程之間的通信媒介稱爲參數傳遞。調用過程中的變量值通過某種機制傳遞給被調用過程。在繼續之前,先複習一些與程序中的值有關的基本術語。

右值

表達式的值稱爲其r值。如果包含在單個變量中的值出現在賦值運算符的右側,則該值也將變爲r值。r值總是可以分配給其他變量。

l值

存儲表達式的內存(地址)的位置稱爲該表達式的l值。它總是出現在賦值運算符的左側。

For example:

day = 1;week = day * 7;month = 1;year = month * 12;

從這個例子中,我們瞭解到常數值(如1、7、12)和變量(如日、周、月和年)都有r值。只有變量纔有l值,因爲它們也表示分配給它們的內存位置。

For example:

7 = x + y;

是一個l值錯誤,因爲常量7不代表任何內存位置。

形式參數Formal Parameters

接受調用方過程傳遞的信息的變量稱爲形式參數。這些變量在被調用函數的定義中聲明。

實際參數Actual Parameters

將其值或地址傳遞給被調用過程的變量稱爲實際參數。這些變量在函數調用中指定爲參數。

Example:

fun_one()
{
int actual_parameter = 10;
call fun_two(int actual_parameter);
}
fun_two(int formal_parameter)
{
print formal_parameter;
}

形式參數保存實際參數的信息,這取決於所使用的參數傳遞技術。它可以是一個值或地址。
傳遞值Pass by Value

在傳遞值機制中,調用過程傳遞實際參數的r值,編譯器將其放入被調用過程的激活記錄中。然後,形式參數保存調用過程傳遞的值。如果形式參數所保留的值發生了更改,則不會對實際參數產生影響。

通過引用傳遞Pass by Reference

在按引用傳遞機制中,實際參數的l值被複制到被調用過程的激活記錄中。這樣,被調用的過程現在擁有實際參數的地址(內存位置),而形式參數引用相同的內存位置。因此,如果更改了形式參數所指向的值,則應該看到對實際參數的影響,因爲它們也應該指向相同的值。
按副本傳遞還原Pass by Copy-restore

此參數傳遞機制的工作原理與“按引用傳遞”類似,只是在調用過程結束時對實際參數進行更改。在函數調用時,實際參數的值被複制到被調用過程的激活記錄中。如果操作了形式參數,則對實際參數沒有實時影響(因爲傳遞了l值),但是當調用過程結束時,形式參數的l值將複製到實際參數的l值。

例子:

Example:

int y;
calling_procedure()
{
y = 10;
copy_restore(y); //l-value of y is passed printf y; //prints 99 }copy_restore(int x)
{
x = 99; // y still has value 10 (unaffected)
y = 0; // y is now 0
}

此函數結束時,形式參數x的l值複製到實際參數y,即使在過程結束前改變了y值,x的l值也複製到y的l值,使其行爲類似於通過引用調用。

按名稱傳遞Pass by Name

像Algol這樣的語言提供了一種新的參數傳遞機制,其工作原理類似於C語言中的預處理器。在按名稱傳遞機制中,被調用的過程的名稱將被其實際主體替換。Pass by name以文本方式將過程調用中的參數表達式替換爲過程主體中的相應參數,以便它現在可以處理實際參數,這與Pass by reference非常類似。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章