天天看點

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

本節書摘來自華章計算機《計算機系統:核心概念及軟硬體實作(原書第4版)》一書中的第2章,第2.1節,作者:[美] j. 斯坦利·沃法德(j. stanley warford)著, 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

計算機隻能執行isa3層(指令集架構層)上的機器語言語句。是以hol6層的語句必須先被翻譯到isa3層,然後才能執行。圖2-1展示了編譯器的功能,它執行從hol6層語言到isa3層語言的翻譯工作。這個圖展示了到第3層的翻譯,有些編譯器是從第6層翻譯到第5層,然後再要求從第5層翻譯到第3層。

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

2.1.1c++編譯器

為了執行本書中的程式,需要有一個c++編譯器。運作程式分為3個步驟:

在文本編輯器中用c++語言寫程式,這個版本叫作源程式。

調用編譯器把源程式從c++翻譯或編譯為機器語言,機器語言的版本叫作目标程式。

執行目标程式。

有些系統允許用一條指令去指定後面的兩個步驟,通常叫作“運作”指令。無論是否分開編譯和執行,hol6層的程式在執行前必須進行翻譯。

當你寫源程式時,它像其他文本文檔一樣儲存在磁盤檔案中。編譯器将生成另一個稱為代碼檔案的目标程式檔案。編譯後目标程式在你的檔案目錄中是否可見取決于你的編譯器。

如果想執行一個之前編譯過的程式,就不需要再翻譯它,隻需直接執行目标程式即可。如果删掉了磁盤上的目标程式,總是可以通過再編譯源程式來恢複它。但是翻譯隻能從高層到低層,如果删除了源程式,那麼不能從目标程式恢複它。

c++編譯器是軟體,不是硬體。它存儲在磁盤上的檔案中。像所有的程式一樣,編譯器有輸入、處理和生成輸出這3個過程。從圖2-2中可以看到編譯器的輸入是源程式,而輸出是目标程式。

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

2.1.2 機器無關性

isa3層語言是與機器相關的。使用isa3層語言寫的用于在x品牌計算機上執行的程式,是不能在y品牌計算機上運作的。hol6層語言的一個重要性質就是它們與機器無關。如果用hol6層語言寫了一個程式用于在x品牌計算機上執行,那麼隻用稍加修改,它就可以在y品牌計算機上運作。

圖2-3展示了c++怎樣實作它的機器無關性。假設用c++寫了一個做統計分析的應用程式。既想把它賣給有x品牌計算機的人,也想把它賣給有y品牌計算機的人。隻有當這個統計程式是機器語言格式時才能執行。因為機器語言是與機器相關的,是以需要2個機器語言的版本:x品牌一種,y品牌一種。因為c++是一種常用的進階語言,是以應該有x品牌機器的c++編譯器和y品牌機器的c++編譯器。如果這樣的話,那麼隻需在一台機器上調用x品牌的c++編譯器生成x品牌機器語言版本,在另一台機器上調用y品牌的c++編譯器生成y品牌機器語言版本,而隻需寫一個c++程式。

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

2.1.3c++的記憶體模型

c++程式設計語言有3種不同類型的變量:全局變量、局部變量和動态配置設定變量。變量的值存儲在計算機的主存中,但是變量存儲的方式取決于變量的類型。3種類型的變量分别對應存儲器中3個特定的區域:

全局變量存放在存儲器中的固定位置。

局部變量存放在運作時棧上。

動态配置設定變量存放在堆上。

全局變量的聲明在所有函數的外面,在程式的執行過程中位置保持不變。局部變量在函數中聲明,函數被調用時它們出現,函數結束時它們消失。動态配置設定變量随着new運算符的執行出現,随着delete運算符的執行消失。

棧是一個值的容器,通過壓入(push)操作存入值,通過彈出(pop)操作取出值。存入和取出值的原則是後進先出,即當從棧中彈出一個值時,取出的是最後一個進入棧的值。正因如此,有時候棧稱為lifo表,lifo是“last in, first out”(後進先出)的首字母縮寫。

每條執行的c++語句是一個函數的一部分。c++函數有一個傳回類型、一個名字和一個參數表。程式包括一個名為main的特殊函數。通過執行main函數中的語句來執行程式。main函數中的語句有可能調用另一個函數。當執行一個函數時,按照如下順序對運作時棧的空間進行配置設定:

壓入傳回值的存儲空間。

壓入參數。

壓入傳回位址。

壓入局部變量的存儲空間。

當函數結束時,按照相反的順序釋放運作時棧的存儲空間:

釋放局部變量。

彈出傳回位址,根據傳回位址确定要執行的下一條語句。

釋放參數。

彈出傳回值,按照調用語句指定方式進行使用。

不管一個函數是main函數,還是在另一個函數中被一條語句調用的函數,都會執行上述這些步驟。

本章的程式說明c++程式設計語言的記憶體模型。後面的章節将展示編譯器把同樣的程式翻譯到asmb5層後的目标代碼。

2.1.4全局變量和指派語句

每個c++變量有3個屬性:

名字。

類型。

值。

變量名是程式員任意确定的辨別符。變量類型指定變量值的可能類型。圖2-4展示的程式聲明了兩個全局變量,輸入它們的值,對它們的值進行操作,然後輸出結果。這個程式沒有實際的意義,它的唯一目的就是說明c++程式的一些特點。

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

圖2-4的前兩行是注釋,編譯器會忽略注釋。c++源程式中的注釋以兩條斜杠//開始直到本行結束。程式接下來的一行是

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

它是一個編譯器指令(compiler direc-tive), 使得程式能夠使用函數庫。在這個例子中,庫檔案iostream包含程式後面要用到的輸入函數>>和輸出函數<<。所有要使用>>和<<的程式都需要這條指令或者類似的指令。語句

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

是使用辨別符cin和cout所必需的,這兩個辨別符是在namespace std中定義的。如果不用using語句,使用cin和cout時就必須用完全限定名(fully qualified name)。例如,main()中的第一行就會寫作

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

程式中接下來的兩行

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

聲明了兩個全局變量。第一個變量的名字是ch,它的類型是字元型,是由變量名前面的關鍵字char來指定的。和大多數變量一樣,聲明并不能确定它的值,而必須從一個輸入語句獲得值。第二個變量的名字是j,類型是整型,由int指定。每個c++程式都有一個包含可執行語句的主函數。在圖2-4中,因為變量是在主程式外聲明的,是以它們是全局變量。

程式中接下來的一行

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

聲明了主程式是一個傳回一個整數的函數。c++編譯器必須生成能在特定作業系統上執行的代碼,由作業系統來解釋傳回值。标準慣例是,傳回值為0表示程式執行中沒有發生錯誤。如果發生了執行錯誤,則程式中斷,然後傳回一些非零的值,不會執行到main()最後一條可執行語句。這種情況下,如何處理取決于作業系統和錯誤的類型。本書中所有的c++程式都遵循通常的慣例:傳回0作為main函數的最後一條可執行語句。

圖2-4中第一條可執行語句是

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

這條語句用輸入運算符>>連接配接cin,cin表示标準輸入裝置。标準輸入裝置可以是鍵盤或者磁盤檔案。在unix環境下,預設的輸入裝置是鍵盤。執行程式時,可以把輸入重定向到一個磁盤檔案。這條輸入語句把輸入流中的第一個值賦給ch,第二個值賦給j。

第二條可執行語句是:

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

c++中的指派運算符是=,在英語中讀作“gets”(意為獲得,在中文裡一般讀作“等于”)。上面這條語句和下面這條是等價的:

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

英文中讀作“j gets j plus five”(意為j的值為j加上5)。

和某些程式設計語言不同,c++把字元當做整數,可以對它們進行運算。下面這條可執行語句

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

用增量運算符對ch加1,它等價于指派語句

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

c++程式設計語言是c語言(它本身是從b語言發展而來)的一個擴充。語言設計者在确定c++這個名字時,就使用了增量運算符。

接下來的可執行語句是

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

這條語句用輸出運算符<<連接配接cout,cout表示标準輸出裝置。标準輸出裝置可以是顯示屏也可以是磁盤檔案。在unix環境下,預設的輸出裝置是顯示屏,執行程式時,可以把輸出重定向到一個磁盤檔案。endl代表“end line”(意為行結束)。這條輸出語句把變量ch的值傳送到輸出裝置,然後把光标移到下一行的開始位置,把變量j的值傳送到輸出裝置,再把光标移到下一行的開始位置。

圖2-5展示了圖2-4所示程式在結束前的記憶體模型。全局變量ch和j的存儲位置是在記憶體的固定位置上配置設定的,如圖2-5a所示。

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

記住,當一個函數被調用時,運作時棧上配置設定了4項:傳回值、參數、傳回位址和局部變量。由于這個程式的主函數沒有參數和局部變量,是以在運作時棧上僅配置設定了标記為retval的傳回值和标記為retaddr的傳回位址的存儲空間,如圖2-5b所示。圖中顯示的傳回位址值是ra0,這是作業系統中程式結束時将執行的指令的位址。對在hol6層的我們來說,os4層作業系統的細節是隐藏的。

2.1.5局部變量

全局變量在主存中的固定位置進行配置設定,而局部變量在運作時棧上進行配置設定。在c++程式中,局部變量在主程式内聲明。圖2-6所示的程式聲明了一個常量和3個局部變量,3個局部變量分别表示一門課程的兩次考試分數和一個總分,總分是兩次考試分數的平均分加上獎勵分。

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

第一個變量之前的是常量bonus。與變量一樣,常量有名字、類型和值。不過,與變量不同的是,常量的值不會改變。初始化運算符=将這個常量的值指定為5。

圖2-6中的第一條可執行語句是

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

它把輸入流中的第一個值賦給exam1,第二個值賦給exam2。第二條可執行語句是

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

它把exam1和exam2的值相加得到的和除以2獲得它們的平均值,再加上獎勵分,接着把這個值賦給變量score。因為exam1、exam2和2都是整數,是以除法運算符/代表整數除法。如果exam1和exam2二者之一被聲明為浮點型,或者除數寫作2.0而不是2,那麼除法運算符就代表浮點數除法。整數除法會截掉餘數,而浮點數除法會保留小數部分。

例2.1如果圖2-6所示程式的輸入是

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

那麼輸出仍然是

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

考試分數和是153。如果用153除以2.0,得到浮點數值76.5。但是,如果用153除以2,運算符/代表整數除法,小數部分被截掉,或者說砍掉,得到76。 □

例2.2如果把score聲明為雙精度浮點型,如下所示

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

并且如果通過将2改為2.0把除法強制為浮點數除法,如下所示

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

那麼當輸入是68和85時,輸出是

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

兩個數的浮點除法僅生成一個值,即商。然而,整數除法生成兩個值—商和餘數,兩者都是整型。可以用c++的模運算符%計算整型除法的餘數。圖2-7展示了一些整型除法和模運算的例子。

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

圖2-8展示了圖2-6所示程式中的局部變量的記憶體模型。計算機在運作時棧上給所有的局部變量配置設定存儲空間。當main()執行時,傳回值、傳回位址、局部變量(exam1、exam2和score) 被壓入棧中。因為bonus不是變量,是以它不會入棧。

《計算機系統:核心概念及軟硬體實作(原書第4版)》——2.1 變量

繼續閱讀