首先,為了在c++中實現反射系統,我認為需要解決以下兩個問題:
(1)根據乙個給定符號,獲取符號對應的位址資訊。
(2)根據位址資訊,能夠對其進行相應操作。
對(2)需要再說明的是:為了能夠對位址指向的物件進行操作,需要一些用於描述這個物件的最基本資訊(比如物件的型別),而這些資訊就是物件的meta資訊。有了meta資訊,我們才能正確的操作物件。
不同型別的物件的meta資訊應該是不同的:
(1)對於簡單的資料成員(int、double、struct等),meta資訊應該包括資料所佔記憶體的布局。通過記憶體布局和記憶體位址,我們可以對其進行get/set操作。
(2)對於函式,meta資訊應該有呼叫慣例(calling conventions)、引數、返回值等資訊。通過這些資訊我們能對函式進行呼叫操作。
(3)對於類,meta資訊可以認為是前兩種的組合。應該包含方法表(函式集合)和資料成員集合。
暫時不考慮剩餘的其他型別,如模板、巨集等。
我以此實現了乙個反射系統的demo。基本做法是,通過windows的dia(debug inte***ce access)api讀取程式的pdb檔案。以此來獲得乙個符號的位址資訊,以及這個符號的基本meta資訊。這樣可以做到根據乙個位址,對資料進行讀寫的操作。但是對函式來說似乎還不夠。為了成功呼叫函式,我們還需要根據函式的呼叫慣例,正確的把引數入棧、並從指定位置獲取返回值等。libffi就是專門幹這事的,但是可惜的是它並不支援msvc:-(
不過好在我熟悉python,知道python也有ctype這個模組來處理ffi(foreign function inte***ce)。把它的原始碼稍作剪裁應該就可以拿來用了。這部分工作挺順利的,瀏覽了一下ctype的實現,發現只需要改非常少的幾處即可。cpython的libffi_msvc在此處:d
目前demo功能比較簡陋,只實現了對資料物件的get/set,以及呼叫全域性的函式。不過對於其他複雜的物件的反射,基本上參考這兩個功能就可以輕鬆的實現了。
具體的使用如下**所示:
1、引導程式對應的pdb檔案
creflmgr refl_mgr;//從pdb檔案載入反射資訊
refl_mgr.loaddatafromfile(g_wszpdbfilename);
2、對基本資料的get/set
//get instance data member
creflobject *refl_obj_bar_c;
refl_mgr.getreflobjectfromparent(refl_obj_bar, l"c
", &refl_obj_bar_c);
creflvalue refl_val_bar_c;
refl_mgr.getclassinstdatamember(&bar, refl_obj_bar_c, &refl_val_bar_c);
printf(
"%d\n
", refl_val_bar_c.m_data.m_i8);
//set instance data member
creflobject *refl_obj_bar_i;
refl_mgr.getreflobjectfromparent(refl_obj_bar, l"i
", &refl_obj_bar_i);
creflvalue refl_val_bar_i;
refl_val_bar_i.m_data.m_i32 = 1024
;refl_mgr.setclassinstdatamember(&bar, refl_obj_bar_i, &refl_val_bar_i);
printf(
"%d\n
", bar.i);
3、呼叫函式
//函式creflobject *refl_obj_func1;
refl_mgr.getreflobjectfromglobal(l
"testcallfunc1
", &refl_obj_func1);
refl_mgr.printreflobject(refl_obj_func1);
std::vector
vargs;
ffi_obj arg1;
arg1.type =ffi_type_sint32;
arg1.value.i32 = 2014
;vargs.push_back(arg1);
ffi_obj arg2;
arg2.type =ffi_type_pointer;
arg2.value.p = (void*)"
hello world";
vargs.push_back(arg2);
ffi_obj ret;
ret.type =ffi_type_void;
refl_mgr.callreflobject(refl_obj_func1, vargs, ret);
當然demo是不完整的,目前我認為還有就幾個未解決的比較重要的問題是:
(1)處理對函式的不正確的呼叫。比如傳入了錯誤的引數、返回值型別指定錯了等。這部分cpython的libffi_msvc也沒有做好,它做的僅僅是在windows下檢測函式呼叫前後堆疊暫存器的位置是否一致,詳見此處。但是僅有這個檢測是不夠的,它並不能有效的防止崩潰問題。我認為最好能做到能對引數、返回值進行型別檢查,如果發現錯誤能列印錯誤,並且不進行函式的呼叫操作。
(2)如何在linux gcc環境下實現。
非嵌入式與嵌入式的區別
非嵌入式是通過軟體控制硬體,軟硬體之間直接聯絡來實現要求。但是一旦硬體發生改變軟體也要改變,為了降低這種偶合度過高的問題,出現了嵌入式。嵌入式在軟體和硬體之間新增了作業系統,軟體通過控制作業系統進而控制硬體,硬體發生改變並不會導致軟體也發生改變,這為軟體開發人員節約了很多時間,並且嵌入式能在已有的硬...
嵌入式 檔案IO的學習
用 實現linux中cp複製的功能 include stdio.h include unistd.h include fcntl.h include string.h intmain int argc,char ar int argc是記錄你在命令列敲入的字串個數,char ar 是存放你寫入是字串...
Tinyxml的嵌入式Linux實現
這兩天專案需要在嵌入式linux系統上實現tinyxml解析簡單的xml檔案,於是在網上查詢並收集了一點資料,現在補充完善!版本 tinyxml 2 6 2.zip 首先修改 makefile檔案 1 將 cxx g 改為 cxx arm linux g cc arm linux gcc ld ar...