第8章:子程序和控制結構——《實踐之路》筆記

抽象定義成一種過程java

名字 映射到複雜的程序片斷python

用途功能角度考慮c++

而非具體實現c#

 

控制抽象:執行良好定義操做數組

數據抽象:表示數據緩存

 

局部變量:執行代碼語句相關的變量安全

參數:輸入數據結構

返回值:輸出閉包

將以上三個限制於子程序做用域內併發

 

子程序表明調用方執行操做:任務委託

 

參數化

傳遞參數:傳遞信息(控制子程序行爲),提供數據(值)

實參在調用時映射到形式參數

形參:子程序內局部變量 ?

 

返回值:函數

不返回:過程

 

大多數要求函數在使用前已有聲明

c沒有

 

聲明:編譯器能夠檢查調用函數簽名是否一致

 

調用序列:調用先後,被調用先後

 

8.1回顧棧佈局

調用棧分配空間問題

 

子程序被調用時,棧頂部分配一個新棧幀活動記錄

包含:實參返回值,簿記信息(返回地址,保存的寄存器),局部變量、臨時值

 

在任意給定時刻棧指針寄存器保存最後一個已用位置,或第一個未用地址

幀指針保存棧頂幀內的一個地址

幀中對象訪問相對幀指針位移尋址

 

對象大小編譯時未知,放在幀頂部大小可變區域地址內情向量保存在某個固定區域

不存在未知大小對象:幀中對象相對棧指針偏移量靜態可知不用幀指針

參數大小編譯時未知:參數放在其餘參數下方大小可變區域,地址與內情向量放在相對幀指針已知偏移量處

          或調用方只傳遞臨時地址與內情向量,被調方複製實參到棧頂可變區域

 圖

 

容許嵌套靜態做用域的語言:

對象可能在外圍子程序

維護靜態鏈,找到這些非局部非全局對象

棧幀包含一個 對詞法上外圍幀引用——靜態鏈(指針)

子程序返回時恢復而保存的幀指針——動態鏈(指針)

 

一個活動的子程序,其外圍子程序是活動的

只有經過外圍子程序才能見到調用內層子程序

 

嵌套定義的子程序,只能從外圍子程序進入。由於函數名對其餘函數不可見。

局部子程序:詞法靜態嵌套關係表示可見性

 

8.2調用序列:完成調用工做的實現

維護子程序調用棧

調用先後處理代碼,被調先後處理代碼

 

進入子程序的過程完成的工做

傳遞參數

保存返回地址

修改程序計數器

修改棧指針分配空間!!

保存子程序可能修改的寄存器值(包括幀指針

修改幀指針,指向新幀棧

執行新幀上的對象初始化代碼

 

離開時的工做

傳遞返回參數返回值

局部變量終結代碼,釋放空間

釋放幀棧(恢復棧指針

恢復保存的幀指針

 

全部工做中一部分只能由調用方完成(只有調用方知道的信息:傳遞參數,返回地址?靜態鏈

其餘能夠共同完成

調用方作工做

被調方作工做:能夠節省空間,子程序不止一次被調用???

##調用樹圖

 

保存恢復寄存器

理想模式:調用方正在使用,而被調方用於其餘目的。則將之保存(寄存器集合的子集

實際:調用方保存全部正在使用的寄存器  被調方保存全部將要修改的寄存器

寄存器分組:調用方保存有價值的一組  被調方改寫沒有價值的一組(可能存在語義一致的資源)

 

靜態鏈維護

一部分維護工做必須由調用方完成:調用方的詞法外層

調用方計算被調方的靜態鏈,做爲隱式參數傳遞

具體分兩種狀況:

1.被調方直接嵌套在內層

被調方靜態鏈引用調用方的棧幀。調用方傳遞幀指針

2.被調方在調用方外k層

調用方對靜態鏈作k次間接引用,傳遞給被調方

 

 

典型調用序列

 

調用方

保存寄存器

計算參數值,移入棧或寄存器

計算靜態鏈,做爲隱式參數傳遞

執行子程序調用指令,跳入子程序,返回地址放在棧,寄存器中

 

被調方

分配

保存原有幀值,賦予新值

保存寄存器

 

子程序結束

 

被調方

返回值移入寄存器或棧

恢復寄存器

恢復fp,sp

跳回返回地址

 

調用方

保存返回值

恢復寄存器

 

優化:

沒有局部變量

不須要幀棧,參數來自寄存器

 

區頭向量

取代靜態鏈的小數組,緩存地址計算結果。空間換時間

 

寄存器窗口滑動

 

內聯展開

增長了代碼量

保持語義(相對宏)

編譯器可瞭解語義,可優化

 

8.3參數傳遞

傳遞值,引用,閉包

 

規則惟一:c

規則不惟一:python?

 

8.3.1參數模式

值調用,傳遞副本。獲得值

 

引用調用:傳遞地址。形參爲實參的新名字,別名

傳遞的必須是左值

 

引用傳遞爲了修改參數

值傳遞+返回值:形參賦值回實參

 

討論值模型與引用模型只對使用值模型的語言有意義

 

變量的引用模型,不必定要求全部對象經過地址訪問。java,python

 

java內部類型值模型,自定義爲引用模型

不管變量是值仍是引用,都經過複製來傳遞

與賦值語句語義一致

 

函數意圖

修改實參

保持實參

 

間接訪問代價

複製對象的代價(大型值)

 

只讀參數:同時得到引用參數的效率值參數的安全性

 

c:const聲明:加工時常量

const指針:保證不引用其餘對象  或  引用的對象不被修改

 

c++

引用參數&

不引用其餘對象  const 指針

引用做爲返回值

 

閉包做爲參數

閉包:子程序的引用,並帶有子程序引用環境

代碼地址+引用環境

帶環境的可調用對象

 

c:指向程序的指針

 

面向對象:模仿閉包行爲,閉包對象,單方法類

 

類是對象:有屬性(靜態方法,類變量)

類是類型:建立類實例對象,提供方法,實例屬性

 

8.3.3特殊目的的參數

 

類似數組:不一樣語言,數組維數邊界約束時間不一樣:編譯時,加工時,執行時

語言中,針對參數的規則  比 針對變量的規則 寬鬆

推遲到運行時肯定形狀的數組參數:類似數組參數,開放數組參數

 

默認參數

提供值:修改函數默認行爲

缺省實參:使用默認值,默認行爲

默認值爲:值,字面量,不可變

    :對象,可變 

 

命名參數:相對於位置參數:關鍵字參數:調用時的按名傳參行爲

混合使用:先位置參數

 

 

可變個數參數表

靜態類型不安全,沒法靜態檢查(不知道個數,不可能檢查)

動態類型安全?運行時檢查,動態檢查

類型安全的靜態類型:要求可變長參數表類型相同

 

8.3.4函數返回

不區分表達式與語句的語言:函數的值=函數體(自己是一個表達式)的值???

顯式return:反作用:函數中止

正交性:返回值類型限定

返回複合值,元組

 

 正交性:弱化限制

設計限制了出現的對象必須知足的特徵:第一類,第二類,第三類   類型  靜態已知

 

8.4泛型子程序模板

須要在不一樣類型對象上使用同一操做

OS:隊列:保存進程、存儲描述符、文件緩衝區、設備控制塊、等

隊列數據結構的特徵數據項的特徵無關

 

8.4.1不一樣的實現方法 

隱式參數多態性:參數類型無描述,但依然是類型安全

類型檢查推遲到運行時

 

顯式多態泛型機制

C++模板

用於建立容器

容器:數據抽象,保存一組對象。操做與對象類型無關(不要求提供接口,要求極少的接口)

 

泛型模塊(或類)須要泛型子程序,實現操做

 

泛型參數:

java c#只容許傳遞類型

ada c++容許傳遞常規類型的值子程序或類

 

泛型代碼:對類型參數的最低特性要求(最小接口)

 

適當的限制條件顯示描述,或編譯器推斷  

編譯器的工做是隱式的  寫於程序正文的是顯示的

 

不一樣的實現方法

Ada c++靜態機制:編譯時 建立使用泛型代碼多個實例,每一個實例獨立代碼副本

C++:安排獨立的類型檢查

優化:共享代碼

 

類型檢查:要求特定的類型——函數簽名(運算符)

     要求提供接口——泛型 

 

java:一個泛型全部實例運行時共享代碼

標準基類object的實例(語義轉化爲子類多態性

子類運行父方法

 

靜態泛型 有共性

泛型    宏

內聯函數  宏

編譯器理解的  過後添加的,預處理器展開

類型檢查

常規做用域規則

 

 

8.4.2泛型參數的約束條件

泛型也是種抽象:接口提供全部信息

Ada,java:限制泛型參數,顯示說明參數類型支持的操做

java:從父類繼承的接口實現

 

c++:摒棄顯示限制,提供參數檢查

參數類型不支持操做:靜態語義錯誤避免隱式使用泛型參數類型的操做

 

 

8.4.3隱式實例化(函數)

泛型函數看作重載(重載是否必定要求函數簽名不相同?須要聲明,須要強類型)

c++隱式實例化規則比 重載子程序 嚴格

編譯器對子程序實參做類型強制

 

8.5異常


子程序調用棧的回退

難以在局部上下文處理

不妨礙正常的流程

錯誤處理移到主流以外

控制轉移

 

致命異常

可恢復異常

 

處理程序異常動態約束:容易形成語義模糊

靜態約束詞法位置約束的代碼塊。做爲原始代碼塊相併存在的補充(if else)。

 

調用點引起異常,調用方(&調用方的調用方)處理

沿動態鏈返回,(依然存在動態約束,可是受限得多)

 

調用方代碼塊(靜態約束)中尋找局部處理程序,檢查匹配,處理/從新拋出/終止並打印

 

沿動態鏈尋找調用方,在調用方代碼塊(靜態環境)尋找局部處理程序

匹配——處理

不匹配——從新引起(傳播)

 

8.5.1異常的定義

預約義異常

異常類型

參數:類的域(字典)

 

try

throw,raise主動引起

 

傳播(接收重發

catch

最終未處理的狀況

 

清理操做:相似調用序列語義(子集),可是未完成工做

離開做用域:內存釋放

 

final

with——exit?

 

8.5.3異常的實現

處理程序連接表棧(解釋數據結構?)

控制進入保護區:處理程序加入表

爲實現沿動態鏈的反向傳播,對於中間層子程序無處理程序隱式處理程序:子程序的後續代碼,從新引起異常

 

編譯時記錄表格:處理程序受保護塊的對應關係(指針)

異常發生:程序計數器key,對錶格折半搜索

特別處理隱式處理程序:返回地址做爲key

 

獨立編譯:各個子程序獨立表格

 

無異常機制:模擬行爲

 

8.6協程

須要閉包,保持環境

繼續:常量,建立後不改變

協程:每次運行時變化跳進時位置爲上次退出時位置

 

一組協程:同時存在的上下文,但每一個時刻只有一個在執行,主函數調用

用於離散時間的模擬

要求順序的完整性檢查,替代深層循環

 

控制權轉移

 獨立的程序計數器

 

線程比協程好用

 

協程是併發的,不能共享棧

 

若是棧幀在堆中分配,能夠避免溢出與內部碎片問題???

但會增長子程序調用開銷

 

仙人掌棧

 

表示協程或進程:上下文塊

 

協程轉移

 

 

8.7事件

程序外部發生

時間不可預測

須要程序響應

 

等待輸入:同步阻斷式

回調函數

處理程序:特定時間調用

 

異步設備活動

中斷機制

切換棧到回調函數

 

信息緩衝區

 

基於線程處理程序

 

事件:單獨控制進程

相關文章
相關標籤/搜索