一個可重入子程序必須滿足下面幾個性質:
1、它不能修改代碼指令。在高級語言中,修改代碼指令是非常難的;但是在匯編語言中,一個程序要修改自己的代碼并不是一件很難的事。
例如:
mov word [cs:$+7], 5 ; 將5復制到前面七個字節(jié)的字中
add ax, 2 ; 前面的語句將2改成了5!
這些代碼在實模式下可以運行,但是在保護模式下的操作系統(tǒng)上不行,因為代碼段被標識為只讀。在這些操作系統(tǒng)上,當執(zhí)行了上面的第一行代碼,程序將被終止。這種類型的程序從各個方面來看都非常差。它很混亂,很難維護而且不允許代碼共享(看下面)。
2、它不能修改全局變量(比如在data和bss段里的數(shù)據(jù))。所有的變量應儲存在堆棧里。
書寫可重入性代碼有幾個好處。
1、一個可重入子程序可以遞歸調用。
2、 一個可重入程序可以被多個進程共享。在許多多任務操作系統(tǒng)上,如果一個程序有許多實例正在運行,那么只有一份代碼的拷貝在內存中。共享庫和DLL(Dynamic Link Libraries,動態(tài)鏈接庫)同樣使用了
這種技術。
3、可重入子程序可以運行在多線程5 程序中。Windows 9x/NT和大多數(shù)類UNIX操作系統(tǒng)(Solaris,Linux,等)都支持多線程程序。
遞歸子程序
這種類型的子程序調用它們自己。遞歸可以是直接的或是間接的。當一個名為foo的子程序在foo內部調用自己就產(chǎn)生直接遞歸。當一個子程序雖然自己沒有直接調用自己,但是其它子程序調用了它,就產(chǎn)生間接遞歸。
例如:子程序foo可以調用bar且bar也可以調用foo。
遞歸子程序必須有一個終止條件。當這個條件為真時,就不再進行遞歸調用了。如果一個子程序沒有終止條件或條件永不為真,那么遞歸將不會結束(非常像一個無窮循環(huán))。
圖4.15展示了一個遞歸求n!的函數(shù)。在C中它可以這樣被調用:
x = fact (3); /* find 3! */
圖4.16展示了上面的函數(shù)調用的最深點的堆棧狀態(tài)。
圖4.17展示了另一個更復雜的遞歸樣例的C語言版而4.18展示了它的匯編語言版。對于f(3),輸出是什么?注意:每一次遞歸調用,ENTER指令都會在堆棧上給新的i值分配空間。因此,f的每一次遞歸調用都有它自己獨立的變量i。若是在data段定義i為一雙字,結果就不一樣了。
回顧一下C變量的儲存類型
C提供了幾種變量儲存類型。
global,全局 這些變量定義在任何函數(shù)的外面,且儲存在固定的內存空間中(在data或bss段),而且從程序的開始一直到程序的結束都存在。缺省情況下,它們能被程序中的任何一個函數(shù)訪問;但是,如果它們被聲明為static,那么只有在同一模塊中的函數(shù)才能訪問它們(也就是說, 依照匯編的術語,這個變量是內部的,不是外部的)。
static,靜態(tài) 在一個函數(shù)中,它們是被聲明為靜態(tài)的局部變量。(不幸的是,C使用關鍵字static有兩種目的!)這些變量同樣儲存在固定的內存空間中(在data或bss段),但是只能被定義它的函數(shù)直接訪問。
automatic,自動 它是定義在一個函數(shù)內的C變量的缺省類型。當定義它們的函數(shù)被調用了,這些變量就被分配在堆棧上,而當函數(shù)返回了又從堆棧中移除。因此,它們沒有固定的內存空間。
register,寄存器 這個關鍵字要求編譯器使用寄存器來儲存這個變量的數(shù)據(jù)。這僅僅是一個要求。編譯器并不一定要遵循。如果變量的地址使用在程序的任意的地方,那么就不會遵循(因為寄存器沒有地址)。同樣,只有簡單的整形數(shù)據(jù)可以是寄存器變量。結構類型不可以;因為它們的大小不匹配寄存器!C編譯器通常會自動將普通的自動變量轉換成寄存器變量,而不需要程序員給予暗示。
volatile,不穩(wěn)定 這個關鍵字告訴編譯器這個變量值隨時都會改變。這就意味著當變量被更改了,編譯器不能做出任何推斷。通常編譯器會將一個變量的值暫時存在寄存器中,而且在出現(xiàn)這個變量的代碼部分使
用這個寄存器。但是,編譯器不能對不穩(wěn)定類型的變量做這種類型的優(yōu)化。一個不穩(wěn)定變量的最普遍的例子就是:它可以被多線程程序的兩個線程修改。考慮下面的代碼:
1 x = 10;
2 y = 20;
3 z = x;
如果x可以被另一個線程修改。那么其它線程可以會在第1行和第3行之間修改x的值,以致于z將不會等于10.但是,如果x沒有被聲明為不穩(wěn)定類型,編譯器就會推斷x沒有改變,然后再將z置為10。
不穩(wěn)定類型的另一個使用就是避免編譯器為一個變量使用一個寄存器。
更多建議: