Assembly 類的概念和樣例介紹

2018-12-04 17:43 更新

C++中的類描述了一個對象類型。一個對象包括數(shù)據成員(data member)和函數(shù)成員(function member)。換句話說就是,它是由跟它相關聯(lián)的數(shù)據和函數(shù)組成的一個struct結構體??紤]在圖 7.13中定義的那個簡單的類。一個Simple類型的變量非常類似于包含一個int成員的標準Cstruct結構體。這些函數(shù)并不會儲存到指定結構體的內存中。但是,成員函數(shù)和其它函數(shù)是不一樣的。


C++類

它們傳遞了一個隱藏的參數(shù)。這個參數(shù)是一個指向成員函數(shù)能起作用的對象的指針。 例如,考慮圖 7.13中的Simple類的成員函數(shù)set_data。如果用C語言來 書寫此函數(shù),這個函數(shù)將像這樣:明確傳遞一個指向成員函數(shù)能起作用的 對象的指針,如圖 7.14所示。使用DJGPP編譯器加上-S選項(gcc和Borland編 譯器也是一樣)來告訴編譯器輸出一個包含此代碼產生的等價的匯編語 言代碼的源文件。對于DJGPP和gcc編譯器,此匯編源文件是以.s擴展 名結尾的,但是不幸的是使用的語法是AT&T匯編語言語法,這種語法 和NASM和MASM語法區(qū)別非常大。(Borland和MS編譯器產生一個以.asm擴展名結尾的源文件,使用的是MASM語法。) 


圖例


圖 7.15展示了將DJGPP的輸 出轉換成NASM語法后的代碼,增加了闡明語句目的的注釋。在第一行 中,注意成員函數(shù)set_data的函數(shù)名被指定為一個改編后的標號,此標號 是通過編碼成員函數(shù)名,類名和參數(shù)后得到的。類名被編碼進去的是因為 其它類中可能也有名為set_data的成員函數(shù),而這兩個成員函數(shù) 必須 使用 不同的標號。參數(shù)之所以被編碼進去是為了類能通過攜帶其它參數(shù)來重載 成員函數(shù)set_data,正如標準的C++函數(shù)。但是,和以前一樣,不同的編 譯器在改編標號時編碼信息的方式也不同。


下面的第2和第3行,出現(xiàn)了熟悉的函數(shù)的開始部分。在第5行,把堆棧 中的第一個參數(shù)儲存到EAX中了。這并 不是參數(shù)x!替代它的是那個隱藏的參數(shù),它是指向此函數(shù)能起作用的對象的指針。第6行將參數(shù)x儲存 到EDX中了,而第7行又將EDX儲存到了EAX指向的雙字中。它是Simple對象 中的data成員,也是這個類中的唯一的數(shù)據,它儲存在Simple結構體中偏 移地址為0的地方。


樣例

這一節(jié)使用了這章中的思想創(chuàng)建了一個C++類:用來描述任意大小的 無符號整形。因為要描述任意大小的整形,所以它需要儲存到一個無符號整形的數(shù)組(雙字的)中??梢允褂脛討B(tài)分配來實現(xiàn)任意大小的整形。雙 字是以相反的方向儲存的 ( 也就是說 ,雙字的最低有效位的下標為0)。 圖 7.16展示了Big_int類的定義。Big_int的大小是通過測量unsigned數(shù) 組的大小得到的,用來儲存它的數(shù)據。此類中的size 數(shù)據成員的偏移地址 為0,而number_成員的偏移為4。 


Big_int類的定義

Big_int類的定義2

圖 7.16: Big_int類的定義


為了簡單化這些例子,只有擁有大小相同的數(shù)組的對象實例才可以相互 進行加減操作。 這個類有三個構造函數(shù)(constructor):第一個構造函數(shù)(第9行)使用了一 個正常的無符號整形來初始化類實例;第二個構造函數(shù)(第18行)使用了一個 包含一個十六進制值的字符串來初始化類實例。第三個構造函數(shù)(第21行)是拷貝構造函數(shù) (copy constructor)。 


Big_int類的算術代碼


因為這里使用的是匯編語言,所以討論的焦點在于加法和減法運算符如何工作。圖 7.17展示了與這些運算符相關的部分頭文件。它們展示了如何創(chuàng)建運算符來調用匯編程序。因為不同的編譯器使用完全不同的名字改編 規(guī)則來改編運算符函數(shù),所以創(chuàng)建了內聯(lián)的運算符函數(shù)來調用C鏈接匯編程序。這就使得在不同編譯器間的移植變得相對容易些,而且和直接調用速 度一樣快。這項技術同樣免去了從匯編中拋出異常的必要!


為什么在這里使用的全部是匯編語言呢?回想一下,在執(zhí)行多倍精 度運算時,進位必須從一個雙字移去與下一個有效的雙字進行加法操作。C++(和C)并不允許程序員訪問CPU的進位標志位。只有通過讓C++獨 立地重新計算出進位標志位后有條件地與下一個雙字進行加法操作,才能執(zhí)行這個加法操作。使用匯編語言來書寫代碼會更有效,因為它可以訪問 進位標志位,可以使用ADC指令來自動將進位標志位加上,這樣做更有道 理。 


為了簡化,只有add_big_ints的匯編程序將在這討論。下面是這個程序 的代碼(來自big_math.asm): 

代碼1

代碼2

代碼3

代碼4

希望,到此刻為止讀者能明白大部分這里的代碼。第25行到27行將Big_int對 象傳遞的指針儲存到寄存器中。記住引用的僅僅是指針。第31行到35行檢查保證三個對象數(shù)組的大小是一樣的。(注意,size_的偏移被加到指針中了,為了訪問數(shù)據成員。)第44行和第46行調整寄存器,讓它們指向被各自對象使用的數(shù)組,用來替代使用對象本身。(同樣,number_的偏移被加到 對象指針中了。) 


在第52行到57行的循環(huán)中,將儲存在數(shù)組里的整形一起相加,首先加的是最低有效的雙字,然后是下一最低有效的雙字, 等等。 多倍精度運算必須以這樣的順序來完成(看小節(jié) 2.1.5)。第59行用來檢查溢出,一旦溢出, 進位標志位將由最后進行加法運算的最高有效位置位。因為數(shù)組里的雙字 是以little endian順序儲存的,所以循環(huán)從數(shù)組的開始處開始,依次向前直到結束。


圖 7.18展示了Big_int的簡單應用的簡短的例子。注意,Big_int常量必 須明確聲明,如第16行。這有兩個原因。首先,沒有轉換構造函數(shù)來將一個無符號整形轉換成Big_int類型。其次,只有相同大小的Big _int數(shù)才能 用來進行相加操作。這里進行類型轉換是有問題的,因為要知道需轉換的大小是非常困難的。此類的一個更高級的實現(xiàn)將允許任意大小的數(shù)之間的相加。作者不打算因為要實現(xiàn)任意大小的數(shù)的相加而把這個例子弄得過度復雜。(但是,鼓勵讀者來實現(xiàn)它。)


Big int的簡單應用


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號