国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
移植最新版libmemcached到VC++的艱苦歷程和經(jīng)驗(yàn)總結(jié)(下)
移植最新版libmemcached到VC++的艱苦歷程和經(jīng)驗(yàn)總結(jié)(下)
2011-10-27     0 個(gè)評(píng)論     
收藏   
我要投稿

 

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

五、gccVC++對(duì)象模型的差異分析:

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

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

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

 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 }

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

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

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

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

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

七、最后的決策:

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

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

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

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

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

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

八、結(jié)束語(yǔ):

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

 

作者 Stephen_Liu

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
跨平臺(tái)C++ MD5類(lèi)庫(kù)
avr單片機(jī) 串口實(shí)現(xiàn)printf(使用變參函數(shù))
POSIX Socket編程
中國(guó)linux公社 - 基于atmel at91rm9200的armlinux的bootloader啟動(dòng)代碼分析
使用Arduino開(kāi)發(fā)ESP32(03):WiFi基本功能使用
【轉(zhuǎn)】基于Android 的GPS 移植
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服