前面從網絡中收藏加轉貼了一部分關於變長參數函數的筆記。反正休閒沒事,因而就專門的研究研究瞭如何用Delphi來實現相似於C語言中Printf這種能夠傳遞任意多個參數的函數。這個實際上來講也不太難,只要俺們都熟悉函數的調用規則,那麼就很容易了。實際上這個變長,整體上來講,應該是有跡可循的。那這個跡象在哪裏,就是關鍵點了,也就是說,最主要的是要知道,這個函數到底傳遞了多少個參數。咱們參看C的,printf和Windows的wsPrintf,都知道,實際上他裏面都有一個Format的參數類型。有這個類型,就能夠根據這個格式參數,來獲取裏面有多少個%d,%s,%f這樣的匹配內容了,因而經過這個,咱們就能夠知道函數到底傳遞了多少個參數了。繼而,俺們就能夠從程序堆棧當中把這些參數一個個的給找出來,而後在俺們的函數中加以處理。那麼這時候確定就有人要問了,爲何參數是在堆棧中。。。。這個。。仍是歸於函數調用法則來講,最初制定的時候,有規定stdcall,pascal,以及Delphi默認的Register調用都是由程序自動管理堆棧,除此以外,還有一種調用方式就是cdecl這個方式,是由咱們本身來平衡堆棧,本身管理的,而動態個數參數的函數,也就必須是這個cdecl的調用方式,這種調用方式,參數是按照從右向左的方式壓入堆棧的,這樣設計是有道理的,從右往左邊壓入,那麼越早傳入的參數就越晚被壓入,那麼咱們就可以知道最有用的實際參數,好比此時若是進入到變長函數,那麼咱們就能夠知道,當前堆棧的棧頂就是咱們的現場,那麼再網上遞歸,就是第一個參數了,也就是說[ebp+8]就是當前的第一個參數了。由此能夠找到第二個參數,第三個參數。。。。。。 網絡
因此,咱們必定要在最初的參數中獲取後面到底實際傳遞了多少個變體參數。而後才能夠經過堆棧,一個個的找到,進而以函數來處理。 函數
說了這麼多來舉例實驗一下。好比,寫一個函數,須要得到傳入的數字的和 oop
function GetSum(NumCount: integer{N1,N2: integer}): Integer;cdecl; asm { push ebp mov ebp,esp } mov ecx,[ebp + 8];//先獲取第一個參數值,判斷傳遞了幾個參數 //而後獲取每一個參數 mov edx,12 mov eax,0 @@add: add eax,[ebp].edx add edx,4 loop @@add end;而後調用方式:
type VA_Sum = function(NumCount: integer{N1,N2}): Integer; cdecl varargs; var m: VA_Sum; begin m := GetSum; ShowMessage(inttostr(m(4,3,4,5,6))); end;在好比,鏈接字符串函數
function ConStr(NumCount: integer{N1,N2}): string;cdecl; var st1: string; i: Integer; begin asm mov esi,16 end; for i := 0 to NumCount - 1 do begin asm mov edi,[ebp].esi cmp edi,128 jb @@char mov DWORD ptr st1,edi @@Char: add esi,4 end; Result := Result + st1; end; end; //調用方法 type VA_ConStr = function(NumCount: integer{N1,N2}): string; cdecl varargs; var cstr: VA_ConStr; begin cstr := constr; ShowMessage(cstr(3,'Test','不得閒','測試')); end;