乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      移植最新版libmemcached到VC++的艱苦歷程和經(jīng)驗(yàn)總結(jié)(下)

       牛人的尾巴 2015-06-15
      移植最新版libmemcached到VC++的艱苦歷程和經(jīng)驗(yàn)總結(jié)(下)
      2011-10-27      0 個評論      
      收藏    我要投稿

       

      結(jié)果如何呢?我的VC++測試用例還是不能調(diào)用該接口的接口方法,只是這次的報錯方式有所改變,提示是每個C/C++程序員最不愿意看到的“內(nèi)存地址訪問違規(guī)”,這一次我確實(shí)被郁悶了,這是為什么呢?

      五、gccVC++對象模型的差異分析:

        在VC++中,C++對象(含有虛函數(shù))在編譯后將生成屬于自己的對象模型,虛擬表vtable和虛擬指針vptr均被包含在該模型中(關(guān)于該問題,可以參考Stanley Lippman的《深度探索C++對象模型》)。而我們目前的設(shè)計方式恰恰是充分利用了vptr和vtable來定位每個接口函數(shù),不幸的是,VC++生成的C++對象的vptr在該對象模型的最開始處,即該對象模型的前4個字節(jié),而gcc則不是這樣存儲vptr的。當(dāng)我們通過vptr定位vtable,再通過vtable的slot定位接口函數(shù)時,也將無法得到我們期望的接口函數(shù)的入口地址,因此調(diào)用結(jié)果可想而知,而且還給人一種關(guān)公戰(zhàn)秦瓊的感覺。

      六、傳統(tǒng)的設(shè)計思路和技巧:

        一條路已經(jīng)走到了死胡同,唯一的辦法就是掉過頭來重新來過。這次我想到的設(shè)計思路非常簡單,也更加傳統(tǒng)。通過之前的失敗經(jīng)驗(yàn)總結(jié),盡管通過VC調(diào)用gcc的純虛接口是不能正常工作的,然而gcc導(dǎo)出的那兩個C函數(shù)卻是可以正常調(diào)用的,同時也得到了正確的調(diào)用結(jié)果。鑒于此,我將設(shè)計一個只是包含封裝函數(shù)(封裝libmemcached的導(dǎo)出函數(shù))的動態(tài)庫,見如下代碼:

       1#define MCWRAPPER_CALL __attribute__((cdecl))
       2
       3 extern "C" {
       4     void* MCWRAPPER_CALL wrapped_memcached_create();
       5     void MCWRAPPER_CALL wrapped_memcached_free(void* p);
       6     void MCWRAPPER_CALL wrapped_memcached_result_free(void* result);
       7     const char* MCWRAPPER_CALL wrapped_memcached_strerror(void* p, int error);
       8     int MCWRAPPER_CALL wrapped_memcached_behavior_set(void *p, const int flag, uint64 data);
       9     int MCWRAPPER_CALL wrapped_memcached_behavior_set_distribution(void* p, int type);
      10     int MCWRAPPER_CALL wrapped_memcached_server_add(void* p,const char* hostname, uint16 port);
      11     uint32 MCWRAPPER_CALL wrapped_memcached_server_count(const void* p);
      12     int MCWRAPPER_CALL wrapped_memcached_set(void* p,const char* key
      13             ,size_t klength,const char* data,size_t dlength);
      14     int MCWRAPPER_CALL wrapped_memcached_add(void* p,const char *key
      15             ,size_t klength,const char* data,size_t dlength);
      16     int MCWRAPPER_CALL wrapped_memcached_replace(void* p,const char* key
      17             ,size_t klength,const char* data,size_t dlength);
      18     int MCWRAPPER_CALL wrapped_memcached_append(void* p,const char* key
      19             ,size_t klength,const char* data,size_t dlength);
      20     char* MCWRAPPER_CALL wrapped_memcached_get(void* p,const char* key,size_t klength
      21             ,size_t* dlength,uint32* flags,int* error);
      22     int MCWRAPPER_CALL wrapped_memcached_mget(void* p,const char* const* keys
      23             ,const size_t* keysLength,size_t numberOfkeys);
      24     void* MCWRAPPER_CALL wrapped_memcached_fetch_result(void* p,void* result,int* error);
      25     const char* MCWRAPPER_CALL wrapped_memcached_result_value(const void* self);
      26     size_t MCWRAPPER_CALL wrapped_memcached_result_length(const void* self);
      27     int MCWRAPPER_CALL wrapped_memcached_delete(void* p,const char* key,size_t klength);
      28     int MCWRAPPER_CALL wrapped_memcached_exist(void* p,const char *key,size_t klength);
      29     int MCWRAPPER_CALL wrapped_memcached_flush(void* p);
      30     int MCWRAPPER_CALL wrapped_memcached_cas(void* p,const char* key,size_t klength
      31             ,const char* data,size_t dlength,uint64 cas);
      32     int MCWRAPPER_CALL wrapped_memcached_increment(void* p,const char* key
      33             ,size_t klength,uint32 step,uint64* value);
      34     int MCWRAPPER_CALL wrapped_memcached_decrement(void* p,const char* key
      35             ,size_t klength,uint32 step,uint64* value);
      36     int MCWRAPPER_CALL wrapped_memcached_increment_with_initial(void* p
      37             ,const char* key,size_t klength,uint64 step,uint64 initial,uint64* value);
      38     int MCWRAPPER_CALL wrapped_memcached_decrement_with_initial(void* p
      39             ,const char* key,size_t klength,uint64 step,uint64 initial,uint64* value);
      40 }

        通過封裝函數(shù)的簽名可以看出,所有和libmemcached相關(guān)的結(jié)構(gòu)體指針在此均被定義為void*類型,這樣就可以規(guī)避上一篇中提到的結(jié)構(gòu)體由不同編譯器生成的字節(jié)對齊問題。最后,在封裝函數(shù)的內(nèi)部只需要將void*轉(zhuǎn)換回其封裝的libmemcached導(dǎo)出函數(shù)參數(shù)期望的結(jié)構(gòu)體指針類型即可,實(shí)現(xiàn)代碼如下:

        1#include <MemcachedFunctionsWrapper.h>
        2 #include <libmemcached/memcached.h>
        3
        4 void* MCWRAPPER_CALL wrapped_memcached_create()
        5 {
        6     return (void*)memcached_create(NULL);
        7 }
        8
        9 void MCWRAPPER_CALL wrapped_memcached_free(void* p)
       10 {
       11     memcached_free((memcached_st*)p);
       12 }
       13
       14 const char* MCWRAPPER_CALL wrapped_memcached_strerror(void* p, int error)
       15 {
       16     return memcached_strerror((memcached_st*)p,(memcached_return)error);
       17 }
       18
       19 int MCWRAPPER_CALL wrapped_memcached_behavior_set(void *p, const int flag, uint64 data)
       20 {
       21     return memcached_behavior_set((memcached_st*)p,(memcached_behavior_t)flag,data);
       22 }
       23
       24 int MCWRAPPER_CALL wrapped_memcached_behavior_set_distribution(void* p, int type)
       25 {
       26     return memcached_behavior_set_distribution((memcached_st*)p
       27         ,(memcached_server_distribution_t)type);
       28 }
       29
       30 int MCWRAPPER_CALL wrapped_memcached_server_add(void* p,const char* hostname, uint16 port)
       31 {
       32     return memcached_server_add((memcached_st*)p,hostname,port);
       33 }
       34
       35 uint32 MCWRAPPER_CALL wrapped_memcached_server_count(const void* p)
       36 {
       37     return memcached_server_count((memcached_st*)p);
       38 }
       39
       40 int MCWRAPPER_CALL wrapped_memcached_set(void* p,const char* key,size_t klength
       41         ,const char* data,size_t dlength)
       42 {
       43     return memcached_set((memcached_st*)p,key,klength,data,dlength,0,0);
       44 }
       45
       46 int MCWRAPPER_CALL wrapped_memcached_add(void* p,const char *key,size_t klength
       47         ,const char* data,size_t dlength)
       48 {
       49     return memcached_add((memcached_st*)p,key,klength,data,dlength,0,0);
       50 }
       51
       52 int MCWRAPPER_CALL wrapped_memcached_replace(void* p,const char* key,size_t klength
       53         ,const char* data,size_t dlength)
       54 {
       55     return memcached_replace((memcached_st*)p,key,klength,data,dlength,0,0);
       56 }
       57
       58 int MCWRAPPER_CALL wrapped_memcached_append(void* p,const char* key,size_t klength
       59         ,const char* data,size_t dlength)
       60 {
       61     return memcached_append((memcached_st*)p,key,klength,data,dlength,0,0);
       62 }
       63
       64 char* MCWRAPPER_CALL wrapped_memcached_get(void* p,const char* key,size_t klength
       65         ,size_t* dlength,uint32* flags,int* error)
       66 {
       67     return memcached_get((memcached_st*)p,key,klength,dlength,flags,(memcached_return_t*)error);
       68 }
       69
       70 int MCWRAPPER_CALL wrapped_memcached_mget(void* p,const char* const* keys
       71         ,const size_t* keysLength,size_t numberOfkeys)
       72 {
       73     return memcached_mget((memcached_st*)p,keys,keysLength, numberOfkeys);
       74
       75 }
       76
       77 void* MCWRAPPER_CALL wrapped_memcached_fetch_result(void* p,void* result,int* error)
       78 {
       79     return (void*)memcached_fetch_result((memcached_st*)p,NULL,(memcached_return_t*)error);
       80 }
       81
       82 const char* MCWRAPPER_CALL wrapped_memcached_result_value(const void* self)
       83 {
       84     return memcached_result_value((const memcached_result_st*)self);
       85 }
       86
       87 size_t MCWRAPPER_CALL wrapped_memcached_result_length(const void* self)
       88 {
       89     return memcached_result_length((const memcached_result_st*)self);
       90 }
       91
       92 int MCWRAPPER_CALL wrapped_memcached_delete(void* p,const char* key,size_t klength)
       93 {
       94     return memcached_delete((memcached_st*)p,key,klength,0);
       95 }
       96
       97 int MCWRAPPER_CALL wrapped_memcached_exist(void* p,const char *key,size_t klength)
       98 {
       99     return memcached_exist((memcached_st*)p,key,klength);
      100 }
      101
      102 int MCWRAPPER_CALL wrapped_memcached_flush(void* p)
      103 {
      104     return memcached_flush((memcached_st*)p,0);
      105 }
      106
      107 int MCWRAPPER_CALL wrapped_memcached_cas(void* p,const char* key,size_t klength
      108         ,const char* data,size_t dlength,uint64 cas)
      109 {
      110     return memcached_cas((memcached_st*)p,key,klength,data,dlength,0,0,cas);
      111 }
      112
      113 int MCWRAPPER_CALL wrapped_memcached_increment(void* p,const char* key
      114         ,size_t klength,uint32 step,uint64* value)
      115 {
      116     return memcached_increment((memcached_st*)p,key,klength,step,value);
      117 }
      118
      119 int MCWRAPPER_CALL wrapped_memcached_decrement(void* p,const char* key
      120         ,size_t klength,uint32 step,uint64* value)
      121 {
      122     return memcached_decrement((memcached_st*)p,key,klength,step,value);
      123 }
      124
      125 int MCWRAPPER_CALL wrapped_memcached_increment_with_initial(void* p
      126         ,const char* key,size_t klength,uint64 step,uint64 initial,uint64* value)
      127 {
      128     return memcached_increment_with_initial((memcached_st*)p,key,klength,step,initial,0,value);
      129 }
      130
      131 void MCWRAPPER_CALL wrapped_memcached_result_free(void* result)
      132 {
      133     memcached_result_free((memcached_result_st*)result);
      134 }
      135
      136 int MCWRAPPER_CALL wrapped_memcached_decrement_with_initial(void* p
      137         ,const char* key,size_t klength,uint64 step,uint64 initial,uint64* value)
      138 {
      139     return memcached_decrement_with_initial((memcached_st*)p,key,klength,step,initial,0,value);
      140 }

        通過gcc在Mingw32的環(huán)境下編譯該代碼文件,并生成相應(yīng)的動態(tài)庫文件(MemcachedFunctionsWrapper.dll),需要說明的是該動態(tài)庫將靜態(tài)依賴之前生成的libmemcached-8.dll,這一點(diǎn)可以在Mingw32下通過ldd命令予以驗(yàn)證。

        剩下需要做的是去除之前聲明的純虛接口,直接導(dǎo)出一個C++的封裝實(shí)現(xiàn)類,在該類的實(shí)現(xiàn)中,同樣利用Windows API中的LoadLibrary和GetProcAddress方法動態(tài)加載之前生成的libmemcached函數(shù)封裝動態(tài)庫(MemcachedFunctionsWrapper.dll)。該C++類的類聲明和上一篇中實(shí)現(xiàn)類的聲明完全一致,這里就不在重復(fù)給出了。測試用例的代碼也基本相同,只是不需要再通過C接口函數(shù)獲取該C++類的對象指針了,而是可以直接將該C++類的頭文件包含進(jìn)測試用例所在的工程,目前之所以這樣做是為了測試方便,一旦順利通過測試用例后,可以再考慮將該C++類放到一個獨(dú)立的VC工程中,并生成相應(yīng)的dll文件,以便該模塊可以被更多其他的VC程序調(diào)用,從而提高了程序整體的復(fù)用性。

        在執(zhí)行測試用例之前,這次的心情不再像上一次那樣興奮,只是默默的等待測試結(jié)果的正確返回。然而此時,在控制臺窗口突然打印出一條libmemcached中的錯誤提示信息,看到該信息后,立刻切換到VMWire虛擬機(jī)中運(yùn)行的Linux,查看memcached守護(hù)進(jìn)程打印出的結(jié)果。出人意料的是,memcached沒有任何反應(yīng),再結(jié)合libmemcached剛剛輸出的錯誤信息,使我馬上意識到測試用例并沒有驅(qū)動libmemcached正常的工作,甚至根本就沒有連接到Linux中的memcached服務(wù)器。想到這里,我首先關(guān)閉了Linux中iptables的防火墻,然后在我的Windows主機(jī)中通過telnet的方式,直接登錄memcached服務(wù)器監(jiān)聽的端口,最后再切換回Linux查看memcached服務(wù)器的反應(yīng),這次memcached輸出了一條客戶端連接的信息,基于此可以證明主機(jī)(Windows)和VMWire虛擬機(jī)中的Linux之間的Socket通訊是正常的。帶著忐忑的心情,再次執(zhí)行了我的測試用例,果不其然,libmemcached輸出了同樣的錯誤信息,Linux端的memcached服務(wù)器也同樣是沒有任何反應(yīng)。

        這時已經(jīng)是深夜了,人的大腦也進(jìn)入了一種麻木的狀態(tài),于是決定上床休息,因?yàn)橹暗慕?jīng)驗(yàn)告訴我,在這個時候離開電腦冷靜的思考往往會分析到問題的本質(zhì),并做出正確的判斷。

      七、最后的決策:

        這一次我的選擇是暫時放棄移植libmemcached到VC的想法,原因如下:

        1. libmemcached版本更新過快,從0.52到0.53的發(fā)布僅僅時隔兩周,而且每兩個版本之間的代碼差異也非常大,甚至代碼的目錄組織結(jié)構(gòu)也是如此,這在我移植0.49和0.53時,體現(xiàn)得非常充分。

        2. 在移植過程中,為了保證順利通過編譯,每個版本都需要進(jìn)行多處修改,而且每個版本修改的地方也不一樣,有意思的是,和0.53相比,0.49需要修改的地方相對較少,移植過程也更加容易。

        3. 修改的方式五花八門,最簡單的就是gcc和VC在C++語法支持上的細(xì)節(jié)差異,這個相對簡單,相信每一個有代碼平臺遷移經(jīng)驗(yàn)的人都會遇到這樣的問題,再有就是沖突問題,比如libmemcached在一個枚舉中包含TRUE、FALSE、ERROR、FLOAT和SOCKET這樣的枚舉成員,不幸的是,它們與windef.h中定義的宏和typedef沖突了,因此我不得不將枚舉中的TRUE改為TRUE1,以此類推。在修改中最讓我擔(dān)心的是需要直接注釋掉一些Windows中不包含的頭文件,而這些文件在Mingw32中也沒有提供。

        4. 調(diào)試相對困難,事實(shí)上在這次遷移0.53的最后,我通過在libmemcached相應(yīng)的函數(shù)中添加printf函數(shù),輸出調(diào)試信息,最終定位并修復(fù)了Socket連接的問題,但是整個過程非常繁瑣,因?yàn)閘ibmemcached是通過gcc編譯的,因此無法在VC的工程中進(jìn)行調(diào)試。當(dāng)然,基于VC的測試用例在gdb下調(diào)試libmemcached也是可以的,對于習(xí)慣使用IDE的人來說,通過命令行方式調(diào)試第三方類庫,其難度可想而知。

        5. 說了這么多,最終的結(jié)果只有一個,Linux下繼續(xù)享用libmemcached和memcached服務(wù)器給我們帶來的成就感,也感謝他們的開發(fā)者無私的奉獻(xiàn)。至于libmemcached for Windows?希望他的作者M(jìn)rs Brian Aker能夠在未來的版本中予以足夠的關(guān)注,也期望libmemcached 1.0版本在發(fā)布時能夠提供VC++的工程文件。

      八、結(jié)束語:

        希望這兩篇文章不僅僅是讓您了解了更多關(guān)于libmemcached的細(xì)節(jié),授人以魚,不如授人以漁,更希望的是與您分享我在基于不同平臺遷移C/C++代碼的經(jīng)驗(yàn)。如果您有更好的方法或技巧,歡迎指正,讓我們來共同提高。總之,分享是快樂的。

       

      作者 Stephen_Liu

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多