從VC6到VC9移植代碼問題總結_第1頁
從VC6到VC9移植代碼問題總結_第2頁
從VC6到VC9移植代碼問題總結_第3頁
從VC6到VC9移植代碼問題總結_第4頁
從VC6到VC9移植代碼問題總結_第5頁
已閱讀5頁,還剩22頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

----------------------------精品word文檔值得下載值得擁有--------------------------------------------------------------------------精品word文檔值得下載值得擁有---------------------------------------------------------------------------------------------------------------------------------------------------------------------------從VC6到VC9移植代碼問題總結當年在學校學習C編程的時候用的是TC2.0,后來學C++用TC3.0,有一天突然發現BorlandC++3.1的IDE比較好用,于是改用BC31,然后是BC4,但是到了BC5(還有BC5.02)的時候就玩不下去了,因為我那臺只有16M內存的P100實在是跑不動這個龐然大物,在OWL和MFC之間“痛苦地”抉擇了一部電影的時間后,我決定放棄添加內存的計劃,改用VisualC++試試。因為當時內存太貴了,不過電影很好看,我還記得名字是《西域雄獅》,講的是黃飛鴻到北美開寶之林分號的故事,還收了一個洋徒。。。你看這思維跳躍的,打住,說正事兒吧。看完電影后裝了一個VisualC++4.2,這Microsoft的東西就是爭氣,在我的破機器上跑得馬溜的快,于是就用買內存的預算買了一本《VisualC++4.0從入門到精通》,那個時候的出版社就是效率低,這本書已經是所有關于VC的書中最新的了,好像還看到一本《VisualC++1.5-2.x使用指南》,什么年代的事情了,還擺在書架上。哪像現在的出版社,簡直就是“與時俱進”的典范,Microsoft那邊《Windows7》剛發布了個預覽版,這邊《下一代xxx揭密》就已經上架了,唉,又扯遠了,打住。沒多久VC5就出來了,好在這兩個版本的用戶界面變化不大(MFC的版本穩定在4.2),我就在《VisualC++4.0從入門到精通》這本書的指導下“精通”了VC5。1998年的時候VisualC++6.0推出了,但是我一直堅持用VC5,1999年我畢業設計還是選擇用VC5,不為別的,就是因為當時盜版的VC6都沒有幫助文件,就是缺少MSDN,沒有這個還怎么寫代碼?畢業設計完成之后我從朋友那里弄到了傳說中的兩張MSDN光盤,于是開始用VC6,從此以后,VC6就一直存在于所有我用過的電腦中,后來VC7(7.1),VC8出來以后,VC6的地位也一直沒有動搖過,用C++開發軟件我首選VC6,我還為VC6開發了一個文件標簽欄插件Tabbar,可以通過標簽欄在打開的代碼文件之間快速切換,除此之外還具有很多其它功能,比如自動打包壓縮項目代碼。。。唉,又跑題了,打住。做人要與時俱進,這不,今年VC9也隨著VisualStudio2008發布了,再不趕上就真的老套了。說是這么說,不過心里還是有些余悸的,2006年的時候我曾經試圖將我的一個工具軟件的代碼升級到VC8,但是我低估了新的編譯器的兼容性(當年從VC5到VC6可是沒有那么多麻煩),上來就是一大堆編譯錯誤,警告就更是牛毛,當時因為急著為工具軟件開發一個新功能,沒有時間解決這些問題,只好放下了,這一放就是兩年。我這個人喜歡自己做工具軟件,目的是為了方便自己,以前用VC6,覺得在代碼源文件之間切換很麻煩,但是WndTab太占用資源,于是就借鑒WndTab的部分代碼自己做了個標簽欄插件Tabbar,還把從CodeProject上看到的好的創意都添加進去,后來用SourceInsight,覺得它沒有文件標簽欄太土,就給它做了個標簽欄外掛(TabSiPlus),就這樣幾年下來竟然有幾百兆的工具代碼,這個移植的工作量可是非同小可,想著都怕怕呀!不過也沒辦法,這兩年主要用GCC做嵌入式開發了,沒有時間維護這些工具,自己在使用過程中累計下來的BUG和新需求也有一大堆,需要進行升級了,適逢這次機會將其移植到VC9到也是個不錯的選擇。其實程序員自己給自己寫工具很有好處,比如我喜歡邊寫代碼邊聽音樂,于是我就把自己寫的MP3播放器集成到VC開發環境中,這樣就可以象操作VC的其它功能一樣選擇音樂文件,還比如。。。又扯遠了,回到正題,講講移植過程中遇到的問題。首先可以直接用VisualStudio2008的打開VC6的工作區文件和項目文件(dsw和dsp),并將其升級為VS2008的解決方案格式和項目格式(sln和vcproj),VC9的編譯器相對于VC6有了很大的變化,一些編譯參數和鏈接參數被廢棄(比如/map:line),有一些改變了名稱,還有新增的選項,不過不用擔心,升級過程會自動對其進行轉換,最終都會得到一個正確的解決方案和VC項目文件,這個過程不會遇到太多的麻煩,問題都出在隨后的編譯過程中,下面就將我在移植的過程中遇到的問題和我的解決方法總結一下,希望對還在用VC6維護代碼的朋友有所幫助。一、_WIN32_WINNT與_WIN32_IE設置沖突_WIN32_WINNT與_WIN32_IE設置不兼容會導致如下C1189致命錯誤:StdAfx.cppc:/programfiles/microsoftsdks/windows/v6.0a/include/sdkddkver.h(217):fatalerrorC1189:#error:_WIN32_WINNTsettingsconflictswith_WIN32_IEsettingStdAfx.cpp通常是項目中第一個編譯的文件,這個錯誤將導致編譯無法繼續進行。產生這個錯誤的原因是原因是_WIN32_WINNT的版本定義太老,老的VC代碼對_WIN32_WINNT的典型設置是:#ifndef_WIN32_WINNT#define_WIN32_WINNT0x0400#endif0x0400相對于VS2008所帶的PlarformSDK(在文件sdkddkver.h中)中_WIN32_IE的定義來說太老了,導致不兼容,可以將其改成0x0501或更高的版本避免這個問題,如下所示:#ifndef_WIN32_WINNT#define_WIN32_WINNT0x0501#endif也可以將這三行_WIN32_WINNT定義刪除,這樣就會使用PlarformSDK中的_WIN32_WINNT定義,自然就不存在不兼容問題了。不過出于對老版本VC的兼容考慮(畢竟以后可能還要使用VC6編譯代碼),最好這樣修改:#if_MSC_VER<=1200//MFC6.0orearlier#ifndef_WIN32_WINNT#define_WIN32_WINNT0x0400#endif#endif二、afximpl.h文件中的語法錯誤MFC出現的時候STL還沒有成為C++的標準,所以MFC使用一套自己的模版庫,比如CArray、CList、CMap等等,這些類型聲明都在afximpl.h文件中。原來在VC6編譯器適用的模版語法可能不適用VC9,特別是當以下四個環境變量設置不兼容時,就會出現這個編譯錯誤,大致情況如下:e:/software/microsoftvisualstudio9.0/vc/atlmfc/src/mfc/afximpl.h(625):errorC2059:syntaxerror:'<L_TYPE_raw>'e:/software/microsoftvisualstudio9.0/vc/atlmfc/src/mfc/afximpl.h(625):errorC2238:unexpectedtoken(s)preceding';'e:/software/microsoftvisualstudio9.0/vc/atlmfc/src/mfc/afximpl.h(629):errorC2059:syntaxerror:'<L_TYPE_raw>'e:/software/microsoftvisualstudio9.0/vc/atlmfc/src/mfc/afximpl.h(629):errorC2238:unexpectedtoken(s)preceding';'合理調整stdafx.h中WINVER、_WIN32_WINNT、_WIN32_WINDOWS和_WIN32_IE的設置可以避免這個問題,將三個與Windows版本有關的環境變量設置為0x0501或更高版本,將IE版本的環境變量設置為0x0500以后的版本就可以解決這個問題。當然,考慮到與舊的VC6代碼兼容,可以采用上一個問題中提到的最后一個解決辦法,用_MSC_VER進行隔離。三、舊的CRT庫和新的安全CRT庫引起的C4996告警解決了環境變量設置不匹配導致的問題后,編譯過程就真正開始了,不過首先映入眼簾的應該是成堆的C4996編譯告警,對每個使用了含字符串參數的CRT庫函數都會有C4996編譯告警,一個典型的輸出如下所示:f:/project/...../commonfunc.cpp(280):warningC4996:'strcpy':Thisfunctionorvariablemaybeunsafe.Considerusingstrcpy_sinstead.Todisabledeprecation,use_CRT_SECURE_NO_WARNINGS.Seeonlinehelpfordetails.e:/software/microsoftvisualstudio9.0/vc/include/string.h(74):seedeclarationof'strcpy'MSDNonline是這樣解釋的:為了顯著增加CRT庫的安全性,許多CRT函數都有了一個更安全的新版本,新版本和舊版本的區別就是新版本函數名多了一個_s后綴。只要一個CRT函數有新的安全版本,編譯器就會產生一個C4996告警,不過,出現這個告警的目的并不是說舊版本的CRT函數將淡出CRT庫,告警出現只是為了提醒程序員這個函數有更安全的版本存在。一種安全的或者是被鼓勵的做法是用安全版本的函數替換現有的CRT函數,不過對于一個有相當代碼量的項目,替換工作量也是巨大的,這可不是用名稱查找、替換就能簡單解決的問題,因為許多安全版本的CRT函數參數個數也發生了變化。也可以用預處理指令消除這個告警:#pragmawarning(disable:4996)或者定義_CRT_SECURE_NO_WARNINGS壓制這個告警(在stdafx.h中define或在項目屬性中設置預處理符號,PreProcessorDefinitions)。除了C語言的CRT函數外,POSIX兼容函數也存在這個告警,解決方法是用POSIX標準名稱替換(比如access換成_access)或者是定義_CRT_NONSTDC_NO_WARNINGS壓制這個告警(方法同上)。四、“CWinApp::Enable3dControls”引起的C4996告警這個是編譯使用了老的向導生成的MFC代碼時遇到的問題,一個典型的告警信息輸出如下所示:CrpFileCrack.cppf:/project/...../crpfilecrack.cpp(52):warningC4996:'CWinApp::Enable3dControls':CWinApp::Enable3dControlsisnolongerneeded.Youshouldremovethiscall.e:/software/microsoftvisualstudio9.0/vc/atlmfc/include/afxwin.h(4818):seedeclarationof'CWinApp::Enable3dControls'通常向導生成的代碼是:#ifdef_AFXDLLEnable3dControls();//CallthiswhenusingMFCinasharedDLL#elseEnable3dControlsStatic();//CallthiswhenlinkingtoMFCstatically#endif這兩個函數的調用是舊的MFC版本對新版本的操作系統特性的支持,在新的(那個時候是新的)Windows95平臺上要這樣調用一下才能使用新的Windows3D樣式的控件,否則就是老的Win3.2樣子的控件。想當初喜歡OWL就是因為感覺它的控件比較“酷”,比如那個帶底紋的對話框,菱形的checkbox,還有帶圖標的“OK”按鈕,看到MFC作出來的灰灰的界面就覺得土,不過后來就知道MFC做界面也是很漂亮的,比如我做的。。。。,再打住。對于新的MFC版本來說已經不需要再調用這兩個函數了,參考前面的方法,用_MSC_VER對其隔離就行了:#if_MSC_VER<=1200//MFC6.0orearlier#ifdef_AFXDLLEnable3dControls();//CallthiswhenusingMFCinasharedDLL#elseEnable3dControlsStatic();//CallthiswhenlinkingtoMFCstatically#endif#endif五、.def文件引起的連接告警對于普通的DLL項目中使用的.def文件通常會引起LNK4017鏈接告警,如下所示:./ComFunc.def(4):warningLNK4017:DESCRIPTIONstatementnotsupportedforthetargetplatform;ignoredCreatinglibrary./../Debug/ComFunc.libandobject./../Debug/ComFunc.exp一個典型的.def文件通常有以下內容:LIBRARY"XorCryptor"DESCRIPTION'XorCryptorWindowsDynamicLinkLibrary'EXPORTS;Explicitexportscangohere..................消除這個連接告警的方法就是從.def文件中刪除DESCRIPTION描述信息,不過這個告警也不是什么大問題,不刪也可以。另一個可能產生的連接告警是LNK4222,通常出現在ocx控件和com組件的項目中,一個典型輸出是:Linking..../PlusInModule.def:warningLNK4222:exportedsymbol'DllCanUnloadNow'shouldnotbeassignedanordinal./PlusInModule.def:warningLNK4222:exportedsymbol'DllGetClassObject'shouldnotbeassignedanordinal./PlusInModule.def:warningLNK4222:exportedsymbol'DllRegisterServer'shouldnotbeassignedanordinal./PlusInModule.def:warningLNK4222:exportedsymbol'DllUnregisterServer'shouldnotbeassignedanordinal出現這個告警的原因是舊的項目的.def文件通常這樣定義ocx和com必需的四個導出函數:EXPORTSDllCanUnloadNow@1PRIVATEDllGetClassObject@2PRIVATEDllRegisterServer@3PRIVATEDllUnregisterServer@4PRIVATE其中為這四個重要的導出函數指定了四個順序號。Windows平臺上通常用兩種方式定位DLL文件中的導出函數,一種是根據導出函數名稱,一種是根據順序號,上學時曾經寫過一個顯示圖片的程序,能處理大多數當時流行的圖像格式文件,唯獨jpeg格式的搞不定,有一次看到一個圖像處理軟件中包含了一個LoadJpeg.dll,很顯然這個DLL是處理jpeg格式的圖像文件的嘛,于是趕快用dependslook了一下,頓時高喊:鬼啊~~~。原來這個depends竟然查不到導出函數的名字,后來才知道還有NONAME參數強制用順序號定位導出函數,于是就常常弄個沒有導出函數名字的DLL到處show。。。。嗯,又扯遠了。話說為什么舊的系統要以此指定這四個導出函數的順序號我就沒有研究了,反正現在不需要指定了,只要將@1,@2之類的刪除就行了,不過不刪好像也沒什么問題,它們會被自動忽略。六、使用MFC的消息映射宏引起的編譯錯誤錯誤現象之一:f:/project/...../plusmaindlg.cpp(220):errorC2440:'static_cast':cannotconvertfrom'void(__thiscallCPlusMainDlg::*)(int,BOOL)'to'LRESULT(__thiscallCWnd::*)(WPARAM,LPARAM)'Noneofthefunctionswiththisnameinscopematchthetargettype錯誤現象之二:f:/project/...../crpfileopavdlg.cpp(87):errorC2440:'static_cast':cannotconvertfrom'LRESULT(__thiscallCCrpFileOpavDlg::*)(LPCTSTR,int)'to'LRESULT(__thiscallCWnd::*)(WPARAM,LPARAM)'Noneofthefunctionswiththisnameinscopematchthetargettype以上兩個編譯錯誤產生是因為新舊版本的MFC中對ON_MESSAGE消息映射宏定義不同引起的,先看看老版本的MFC的ON_MESSAGE消息宏定義:#defineON_MESSAGE(message,memberFxn)/{message,0,0,0,AfxSig_lwl,/(AFX_PMSG)(AFX_PMSGW)(LRESULT(AFX_MSG_CALLCWnd::*)(WPARAM,LPARAM))&memberFxn},再看看新版本的ON_MESSAGE定義:#defineON_MESSAGE(message,memberFxn)/{message,0,0,0,AfxSig_lwl,/(AFX_PMSG)(AFX_PMSGW)/(static_cast<LRESULT(AFX_MSG_CALLCWnd::*)(WPARAM,LPARAM)>/(memberFxn))},注意,函數類型沒有變化,都是:LRESULT(AFX_MSG_CALLCWnd::*)(WPARAM,LPARAM);類型的函數指針(CWnd以及派生類的類成員函數指針),區別之處是新的ON_MESSAGE宏使用C++的static_cast操作符代替了C類型的強制轉換。產生這兩個錯誤其實是因為用戶沒有按照ON_MESSAGE宏的約定聲明和定義消息響應函數造成的,比如,對于某些不需要處理返回值的消息響應函數,用戶通常這樣聲明和定義消息響應函數:在頭文件中聲明:afx_msgvoidOnFileProcess(WPARAMwParam,LPARAMlParam);在源文件中實現:voidCCrpFileOpavDlg::OnFileProcess(WPARAMwParam,LPARAMlParam){.......}或者更過分一些,直接指定為實際參數類型:在頭文件中聲明:afx_msgvoidOnFileProcess(LPCTSTRlpszMessage,intnPercent);在源文件中實現:voidCCrpFileOpavDlg::OnFileProcess(LPCTSTRlpszMessage,intnPercent){.......}舊版本的ON_MESSAGE使用了C類型的強制轉換,宏解開后的代碼后不會產生錯誤信息,但是改成對類型檢查很嚴格的static_cast操作符時就出問題了,因為通不過static_cast操作符的檢查。解決方法就是修改代碼,同時吸取教訓,普遍使用的方法并不一定就能約定俗成,一切還是要按照規矩來。錯誤現象之三:f:/project/...../WzButton.cpp(74):errorC2440:'static_cast':cannotconvertfrom'UINT(__thiscallCWzButton::*)(CPoint)'to'LRESULT(__thiscallCWnd::*)(CPoint)'Castfrombasetoderivedrequiresdynamic_castorstatic_cast出現這個錯誤的原因可是“人力不可抗拒”之原因造成的,因為舊版本的ON_WM_NCHITTEST宏使用了UINT(__thiscallCWzButton::*)(CPoint);類型的類成員函數指針,其定義如下:#defineON_WM_NCHITTEST()/{WM_NCHITTEST,0,0,0,AfxSig_wp,/(AFX_PMSG)(AFX_PMSGW)(UINT(AFX_MSG_CALLCWnd::*)(CPoint))&OnNcHitTest},但是新版本變成了:#defineON_WM_NCHITTEST()/{WM_NCHITTEST,0,0,0,AfxSig_l_p,/(AFX_PMSG)(AFX_PMSGW)/(static_cast<LRESULT(AFX_MSG_CALLCWnd::*)(CPoint)>(&ThisClass::OnNcHitTest))},注意返回值類型由UINT改成了LRESULT,再加上static_cast的嚴格檢查,所以就出錯了。修改的方法就是將你的OnNcHitTest函數由:afx_msgUINTOnNcHitTest(CPointpoint);改成:afx_msgLRESULTOnNcHitTest(CPointpoint);不必太在意,這個不是你的錯,不過,如果你要維護一個老的界面庫(通常很多控件的subclass都會用到ON_WM_NCHITTEST),改起來還是很痛苦地,不扯了,繼續下一個。七、statreg.cpp和atlimpl.cpp的廢棄(obsolete)問題在編譯老的ATL向導生成的代碼時,會遇到下面的編譯輸出:StdAfx.cppstatreg.cppisobsolete.Pleaseremoveitfromyourproject.atlimpl.cppisobsolete.Pleaseremoveitfromyourproject.因為老的ATL向導生成的代碼通常在stdafx.cpp文件中添加以下代碼:#ifdef_ATL_STATIC_REGISTRY#include<statreg.h>#include<statreg.cpp>#endif#include<atlimpl.cpp>根據提示刪除#include<statreg.cpp>和#include<atlimpl.cpp>兩行代碼就行了,不過更好的辦法是這樣改:#ifdef_ATL_STATIC_REGISTRY#include<statreg.h>#if_MSC_VER<=1200//MFC6.0orearlier#include<statreg.cpp>#endif#endif#if_MSC_VER<=1200//MFC6.0orearlier#include<atlimpl.cpp>#endif八、新的C++編譯器不再支持默認類型的變量定義錯誤現象是:f:/project/...../WzCheckBox.cpp(464):errorC4430:missingtypespecifier-intassumed.Note:C++doesnotsupportdefault-int產生這個錯誤的原因是程序中出現了這樣的代碼:constsome_const_var=10;或staticsome_static_bool=FALSE;新的C++編譯器嚴格按照C++標準,不再支持默認類型的變量定義方式,必須嚴格指定變量類型,如下使用:constintsome_const_var=10;或staticBOOLsome_static_bool=FALSE;九、for語句的變量作用域問題考察下面的代碼:for(inti=0;i<120;i++){if(something_happen){break;}.............}if(i<120){//somethinghappen}在VC6的編譯器中,這樣的代碼是沒有問題的,因為VC6的編譯器為了兼容舊的MicrosoftC/C++編譯器,沒有嚴格按照C++標準執行,但是從VC7開始,VC的編譯器開始遵守C++標準,所以就會出現“變量i沒有定義的錯誤”。解決的方法也很簡單,按照JimHyslop和HerbSutter的經典對話系列的第四篇中的方法,改成如下就可以了:inti;for(i=0;i<120;i++)十、字符串函數的返回值問題strchr(_tcschr)、strpbrk(_tcspbrk??)、strrchr(_tcsrchr)和strstr(_tcsstr)這四個函數在VC6的CRT庫中定義的返回值都是char*(TCHAR*),所以以前的代碼通常是這樣使用的:TCHAR*cp=_tcschr(pszPath,_T('//'));//使用*cp,可以通過cp指針修改pszPath的內容這其實是一個“漏洞”,因為如果pszPath是constchar(TCHAR)*字符串,那么就表示它不希望修改字符串的內容,但是調用strchr(_tcschr)函數后就可以通過cp指針修改其內容了,這豈不荒謬?所有在新版本的CRT庫中,這幾個函數的返回值都改成constchar*,這就會導致上面的代碼產生編譯錯誤。建議的修改方式是改成如下方式:constTCHAR*cp=_tcschr(pszPath,_T('//'));//不能再通過cp指針修改pszPath的內容但是這樣修改可能對代碼的影響比較大,比如下面的代碼:TCHARbuf[256];//局部緩沖區......TCHAR*cp=_tcschr(buf,_T('//'));//作為局部緩沖區(非const),希望通過cp修改buf的內容這種情況怎么辦呢?對了,C++還有個const_cast操作符,這時就可以排上用場了:TCHAR*cp=const_char<TCHAR*>(_tcschr(buf,_T('//')));不過上面的方法要慎用,除非確定buf是非const的,否則最好老老實實地修改代碼。十一、類成員函數指針做為函數參數的“C3867”錯誤考察下面的代碼,CWzWindowsHook類的構造函數使用一個該類的成員函數指針,這樣構造對象時可以選擇消息過濾的handler,可以是MouseMsgFilter,也可以是KeyboardMsgFilter:typedefBOOL(CWzWindowsHook::*FILTERPROC)(WPARAMwParam,LPARAMlParam);//Ahookusedincustomizationsheettofilterkeyboard/mouseeventsclassCWzWindowsHook{private:FILTERPROCm_pFilter;BOOLMouseMsgFilter(WPARAMwParam,LPARAMlParam);BOOLKeyboardMsgFilter(WPARAMwParam,LPARAMlParam);public:CWzWindowsHook(FILTERPROCpFilter):m_pFilter(pFilter)舊的遺留代碼存在這樣的用法:CWzWindowsHookmouseHooker(CWzWindowsHook::MouseMsgFilter);在VC6的編譯器下編譯可能沒有問題,但是在VC9的編譯器下編譯會有如下報錯:f:/project/...../WzWindowsHook.cpp(272):errorC3867:'CWzWindowsHook::MouseMsgFilter':functioncallmissingargumentlist;use'&CWzWindowsHook::MouseMsgFilter'tocreateapointertomember雖然C++從C繼承來了函數名即是函數地址的語法規則,但是根據C++的標準,類成員函數的指針仍然需要一個取地址符“&”。解決方法很簡單,按照提示改成如下代碼即可:CWzWindowsHookmouseHooker(&CWzWindowsHook::MouseMsgFilter);十二、wchar_t*類型與USHORT*的轉換錯誤VC6的編譯器不支持wchar_t數據類型,wchar_t實際上被定義成unsignedshort,VC9的編譯器已經支持wchar_t為內置數據類型,但是由一個編譯選項控制,這個選項默認是打開的,也就是將wchar_t作為編譯器的內置數據類型。但是OLECHAR和WCHAR的定義仍然是unsignedshort,在VC6的編譯環境中,兩者的指針都是USHORT*,相互賦值和做為函數參數傳遞沒有問題,但是如果wchar_t作為編譯器的內置數據類型,那就意味著wchar_t*與OLECHAR*或WCHAR*是兩種不同類型的指針,相互賦值就會報編譯錯誤,下面的信息就是一個典型的錯誤輸出:f:/project/...../shellpidl.cpp(290):errorC2664:'MultiByteToWideChar':cannotconvertparameter5from'USHORT*'to'LPWSTR'Typespointedtoareunrelated;conversionrequiresreinterpret_cast,C-stylecastorfunction-stylecast解決的方法就是使用C++的reinterpret_cast操作符或使用C-style強制轉換,當然也可以在項目屬性設置中關閉前面提到的那個選項(這個偶美試過,不知道會不會有其它問題)。編譯時出現“operator+=”不明確,也就是StringData+=nChar;改正方法:pDoc->StringData+=(char)nChar,因為系統里面存在一個wchar_t的類型,所以如果支持了這個類型的話,從unsignednt轉換到wchar_t和char的等級都是標準轉換,所以編譯器無法判斷到底應該轉換到哪一個,故而導致了這個問題 intx1=m_strLine.Find(''); CStringy1=_T(""); y1.Format(_T("%d"),x1); MessageBox(y1); CString轉int

CStringb="123";

inti;

i=_ttoi(b);//在使用多字符集下_atoi(arraytointeger的縮寫)函數是一個好的選擇,它也很少會是一個正確的選擇。而在使用Unicode字符,你應該用_ttoi(),它在ANSI編碼系統中被編譯成_atoi()int型轉CString型

CStringa;

intb=20;

a.Format(_T("%d"),b);//_T宏可以把一個引號引起來的字符串,根據你的環境設置,使得編譯器會根據編譯目標環境選擇合適的(Unicode還是ANSI)字符處理方式,TEXT,_TEXT和_T是一樣的CString型轉double型

CStringstrs;

doublef;

f=_ttol(strs);CString型轉float型

CStringstrs;

floatflt;

flt=(float)atof((char*)(LPTSTR)(LPCTSTR)strs);===============================================================================CString,char*,const

char

*,LPCTSTR

的轉換

如何將CString類型的變量賦給char*類型的變量

1、GetBuffer函數:

使用CString::GetBuffer函數。

char*p;

CStringstr="hello";

p=str.GetBuffer(str.GetLength());

str.ReleaseBuffer();將CString轉換成char*時

CStringstr("aaaaaaa");

strcpy(str.GetBuffer(10),"aa");

str.ReleaseBuffer();

當我們需要字符數組時調用GetBuffer(intn),其中n為我們需要的字符數組的長度.使用完成后一定要馬上調用ReleaseBuffer();

還有很重要的一點就是,在能使用constchar*的地方,就不要使用char*2、memcpy:

CStringmCS=_T("cxl");

charmch[20];

memcpy(mch,mCS,20);3、用LPCTSTR強制轉換:盡量不使用

char*ch;

CStringstr;

ch=(LPSTR)(LPCTSTR)str;CStringstr="good";

char*tmp;

sprintf(tmp,"%s",(LPTSTR)(LPCTSTR)str);4、

CStringMsg;

Msg=Msg+"abc";

LPTSTRlpsz;

lpsz=newTCHAR[Msg.GetLength()+1];

_tcscpy(lpsz,Msg);

char*psz;

strcpy(psz,lpsz);

CString類向constchar*轉換

chara[100];

CStringstr("aaaaaa");

strncpy(a,(LPCTSTR)str,sizeof(a));

或者如下:

strncpy(a,str,sizeof(a));

以上兩種用法都是正確地.因為strncpy的第二個參數類型為constchar*.所以編譯器會自動將CString類轉換成constchar*.CString轉LPCTSTR(constchar*)

CStringcStr;

constchar*lpctStr=(LPCTSTR)cStr;LPCTSTR轉CString

LPCTSTRlpctStr;

CStringcStr=lpctStr;將char*類型的變量賦給CString型的變量

可以直接賦值,如:

CStringmyString="Thisisatest";

也可以利用構造函數,如:

CStrings1("Tom");將CString類型的變量賦給char[]類型(字符串)的變量

1、sprintf()函數

CStringstr="good";

chartmp[200];

sprintf(tmp,"%s",(LPCSTR)str);

(LPCSTR)str這種強制轉換相當于(LPTSTR)(LPCTSTR)str

CString類的變量需要轉換為(char*)的時,使用(LPTSTR)(LPCTSTR)str然而,LPCTSTR是constchar*,也就是說,得到的字符串是不可寫的!將其強制轉換成LPTSTR去掉const,是極為危險的!

一不留神就會完蛋!要得到char*,應該用GetBuffer()或GetBufferSetLength(),用完后再調用ReleaseBuffer()。2、strcpy()函數

CStringstr;

charc[256];

strcpy(c,str);charmychar[1024];

CStringsource="Hello";

strcpy((char*)&mychar,(LPCTSTR)source);

UNICODE下寬字符的CString轉換為constchar*一、使用函數_tcscpy_s:CStringtheString("Thisisatest");

int

sizeOfString=(theString.GetLength()+1);

LPTSTR

lpsz=newTCHAR[sizeOfString];

_tcscpy_s(lpsz,sizeOfString,theString);最后再轉換一下lpsz為const型的LPTSTR在UNICODE環境下編譯是wchar_t類型

二、CStringstr=_T("HelloWorld!");charszStr[256]={0};wcstombs(szStr,str,str.GetLength());constchar*p=szStr;

if($!=jQuery){$=jQuery.noConflict();}================================================= intnum1,num2,num3; TCHARch1[10],ch2[10],ch3[10]; GetDlgItem(IDC_EDIT1)->GetWindowText(ch1,10); GetDlgItem(IDC_EDIT2)->GetWindowText(ch2,10); num1=_ttoi(ch1); num2=_ttoi(ch2); num3=num1+num2; _itot(num3,ch3,10); GetDlgItem(IDC_EDIT3)->SetWindowText(ch3); intx1=m_strLine.Find(''); CStringy1=_T(""); y1.Format(_T("%d"),x1); MessageBox(y1); 你好,你的理解大體上是正確的。你拿過pDC來用,讓它給你輸出你設置的字體,但是用完以后,是要歸還的,還要把它設置成原來那個字體,不然之前調用pDC的地方就會還按這個字體輸出文字了。解釋如下CFont*pOldFont=pDC->SelectObject(&m_font);//保留原來的字體指針到pOldFont中。(SelectObject這個函數會返回原有指針)pDC->TextOut(0,0,m_fontname);//輸出你的字體的文字pDC->SelectObject(pOldFont);//設置pDC到原有字體指針如何為工具欄添加單獨的響應函數?要改三個地方

在view或者doc類里類函數里面添加類似

afx_msgvoidOnButtonZoomIn();//函數聲明

在其cpp中添加關聯

ON_COMMAND(ID_BUTTON_ZOOMIN,&CScaleMapView::OnButtonZoomIn)

最后添加函數

voidCScaleMapView::OnButtonZoomIn()//函數實現

{

}CToolBar:----DockControlBar();

CMFCToolBar:DockPane()不能轉換void(_thiscallCMainFrame::*)(void)toLRESULT(__thiscallCWnd::*)(WPARAM,LPARAM)開發平臺由VC6.0升級至VS2005,需要將原有的項目遷移。可能碰到類似錯誤:

errorC2440:'static_cast':cannotconvertfrom'void(__thiscallCMainFrame::*)

(void)'to'LRESULT(__thiscallCWnd::*)(WPARAM,LPARAM)'

VS2005對消息的檢查更為嚴格,以前在VC6下完全正常運行的消息映射在VS2005下編譯不通過

ON_MESSAGE(WM_message,OnMyMessage);

OnMyMessage返回值必須為LRESULT,其形式為:afx_msgLRESULTOnMyMessage(WPARAM,LPARAM);如果不符合,則有錯誤提示:

errorC2440:“static_cast”:無法從“void(__thiscallCPppView::*)(WPARAM,LPARAM)”轉換為“LRESULT(__thiscallCWnd::*)(WPARAM,LPARAM)”在匹配目標類型的范圍內沒有具有該名稱的函數

errorC2440:“static_cast”:無法從“void(__thiscallCPppView::*)

(void)”轉換為“LRESULT(__thiscallCWnd::*)(WPARAM,LPARAM)”在匹配目標類型的范圍內沒有具有該名稱的函數

解決方法如下:例如:TransparentWnd.cpp中ON_MESSAGE(WM_LIBEN,OnLiben):第一:把原來的消息函數返回值類型改為LRESULT(找到OnLiben定義,如Viod

CTransparentWnd::OnLiben(WPARAMwParam,LPARAMlParam)改成LRESULTCTransparentWnd::OnLiben(WPARAMwParam,LPARAMlParam),聲明處也要改,如afx_msgLRESULTOnLiben(WPARAMwParam,LPARAMlParam););第二:函數內可以隨便寫個returnTRUE;第三:然后消息函數的參數必須改寫成(WPARAMwParam,LPARAMlParam)而不論這兩個參數是否用得到;第四:消息映射如ON_MESSAGE(WM_message,&OnMyMessage下面是古文鑒賞,不需要的朋友可以下載后編輯刪除!!謝謝!!九歌·湘君

屈原

朗誦:路英

君不行兮夷猶,蹇誰留兮中洲。

美要眇兮宜修,沛吾乘兮桂舟。

令沅湘兮無波,使江水兮安流。

望夫君兮未來,吹參差兮誰思。

駕飛龍兮北征,邅吾道兮洞庭。

薜荔柏兮蕙綢,蓀橈兮蘭旌。

望涔陽兮極浦,橫大江兮揚靈。

揚靈兮未極,女嬋媛兮為余太息。

橫流涕兮潺湲,隱思君兮陫側。

桂棹兮蘭枻,斫冰兮積雪。

采薜荔兮水中,搴芙蓉兮木末。

心不同兮媒勞,恩不甚兮輕絕。

石瀨兮淺淺,飛龍兮翩翩。

交不忠兮怨長,期不信兮告余以不閑。

朝騁騖兮江皋,夕弭節兮北渚。她含著笑,切著冰屑悉索的蘿卜,

她含著笑,用手掏著豬吃的麥糟,

她含著笑,扇著燉肉的爐子的火,

她含著笑,背了團箕到廣場上去

曬好那些大豆和小麥,

大堰河,為了生活,

在她流盡了她的乳液之后,

她就用抱過我的兩臂,勞動了。

大堰河,深愛著她的乳兒;

在年節里,為了他,忙著切那冬米的糖,

為了他,常悄悄地走到村邊的她的家里去,

為了他,走到她的身邊叫一聲“媽”,

大堰河,把他畫的大紅大綠的關云長

貼在灶邊的墻上,

大堰河,會對她的鄰居夸口贊美她的乳兒;

大堰河曾做了一個不能對人說的夢:

在夢里,她吃著她的乳兒的婚酒,

坐在輝煌的結彩的堂上,

而她的嬌美的媳婦親切的叫她“婆婆”

…………

大堰河,深愛她的乳兒!

大堰河,在她的夢沒有做醒的時候已死了。

她死時,乳兒不在她的旁側,

她死時,平時打罵她的丈夫也為她流淚,

五個兒子,個個哭得很悲,

她死時,輕輕地呼著她的乳兒的名字,

大堰河,已死了,

她死時,乳兒不在她的旁側。

大堰河,含淚的去了!

同著四十幾年的人世生活的凌侮,

同著數不盡的奴隸的凄苦,

同著四塊錢的棺材和幾束稻草,

同著幾尺長方的埋棺材的土地,

同著一手把的紙錢的灰,

大堰河,她含淚的去了。

這是大堰河所不知道的:

她的醉酒的丈夫已死去,

大兒做了土匪,

第二個死在炮火的煙里,

第三,第四,第五

而我,我是在寫著給予這不公道的世界的咒語。

當我經了長長的飄泊回到故土時,

在山腰里,田野上,

兄弟們碰見時,是比六七年

鳥次兮屋上,水周兮堂下。

捐余玦兮江中,遺余佩兮澧浦。

采芳洲兮杜若,將以遺兮下女。

時不可兮再得,聊逍遙兮容與。

注釋

①湘君:湘水之神,男性。一說即巡視南方時死于蒼梧的舜。

②君:指湘君。夷猶:遲疑不決。

③蹇(jian3簡):發語詞。洲:水中陸地。

④要眇(miao3秒):美好的樣子。宜修:恰到好處的修飾。

⑤沛:水大而急。桂舟:桂木制成的船。

⑥沅湘:沅水和湘水,都在湖南。無波:不起波浪。

⑦夫:語助詞。

⑧參差:高低錯落不齊,此指排簫,相傳為舜所造。

⑨飛龍:雕有龍形的船只。北征:北行。

⑩邅(zhan1沾):轉變。洞庭:洞庭湖。

⑾薜荔:蔓生香草。柏(bo2伯):通“箔”,簾子。蕙:香草名。綢:帷帳。

⑿蓀:香草,即石菖蒲。橈(rao2饒):短槳。蘭:蘭草:旌:旗桿頂上的飾物。

⒀涔(cen2岑)陽:在涔水北岸,洞庭湖西北。極浦:遙遠的水邊。

⒁橫:橫渡。揚靈:顯揚精誠。一說即揚舲,揚帆前進。

⒂極:至,到達。

⒂女:侍女。嬋媛:眷念多情的樣子。

⒃橫:橫溢。潺湲(yuan2援):緩慢流動的樣子。

⒅陫(pei2培)側:即“悱惻”,內心悲痛的樣子。

(19)櫂(zhao4棹):同“棹”,長槳。枻(yi4弈):短槳。

(20)斲(zhuo2琢):砍。

(21)搴(qian1千):拔取。芙蓉:荷花。木末:樹梢。

(22)媒:媒人。勞:徒勞。

(23)甚:深厚。輕絕:輕易斷絕。

(24)石瀨:石上急流。淺(jian1間)淺:水流湍急的樣子。

(25)翩翩:輕盈快疾的樣子。

(26)交:交往。

(27)期:相約。不閑:沒有空閑。

(28)鼂(zhao1招):同“朝”,早晨。騁騖(wu4務):急行。皋:水旁高地。

(29)弭(mi3米):停止。節:策,馬鞭。渚:水邊。

(30)次:止息。(31)周:周流。

(32)捐:拋棄。玦(jue1決):環形玉佩。

(33)遺(yi2儀):留下。佩:佩飾。醴(li3里):澧水,在湖南,流入洞庭湖。

(34)芳洲:水中的芳草地。杜若:香草名。

(35)遺(wei4味):贈予。下女:指身邊侍女。

(36)聊:暫且。容與:舒緩放松的樣子。

譯文

君不行兮夷猶,

神君遲疑猶豫徘徊不肯向前,

蹇誰留兮中洲?

你為誰滯留在水中的島上呢?

美要眇兮宜修,

我容顏妙麗裝飾也恰倒好處,

沛吾乘兮桂舟。

急速地乘坐上我那桂木小舟。

令沅、湘兮無波,

叫沅湘之水柔媚得波瀾不生,

使江水兮安流。

讓長江之水平靜地緩緩前行。

望夫君兮未來,

盼望著你啊你為何還不到來,

吹參差兮誰思!

吹起洞簫寄托我的思念之情!

駕飛龍兮北征,

用飛龍駕舟急速地向北行駛,

邅吾道兮洞庭。

改變我的道路引舟直達洞庭。

薜荔柏兮蕙綢,

用薜荔做門簾用蕙草做床帳,

蓀橈兮蘭旌。

以香蓀裝飾船槳以蘭草為旗。

望涔陽兮極浦,

遙望涔陽啊在那遼遠的水邊,

橫大江兮揚靈。

大江橫陳面前彰顯你的威靈。

揚靈兮未極,

難道你的威靈彰顯還沒終止?

女嬋媛兮為余太息!

我心中為你發出長長的嘆息。

橫流涕兮潺湲,

眼中的清淚似小溪潺潺流下,

隱思君兮陫側。

暗地里思念你心中充滿悲傷。

桂棹兮蘭枻,

想用桂木作成槳蘭木作成舵,

斫冰兮積雪。

劈開你堅冰積雪也似的情懷。

采薜荔兮水中,

卻似在水中采集陸生的薜荔,

搴芙蓉兮木末。

更似爬樹梢采摘水生的芙蓉。

心不同兮媒勞,

兩心不相通讓媒妁徒勞無功,

恩不甚兮輕絕。

恩愛不深切就會輕易的斷絕。

石瀨兮淺淺,

留連著沙石灘上淺淺的流水,

飛龍兮翩翩。

等待著你駕著飛龍翩然降臨。

交不忠兮怨長,

你交情不忠徒增我多少幽怨,

期不信兮告余以不間。

既相約又失信卻說沒有時間。

朝騁騖兮江皋,

早晨我駕車在江邊急急奔馳,

夕弭節兮北渚。

晚間我停鞭在北岸灘頭休息。

鳥次兮屋上,

眾鳥棲息在這空閑的屋頂上,

水周兮堂下。

空屋的四周有流水迂緩圍繞。

捐余玦兮江中,

將你贈的玉制扳指置于江中,

遺余佩兮澧浦。

將你贈的玉佩放在澧水岸邊。

采芳洲兮杜若,

采來香草裝飾這芬芳的洲瀆,

將以遺兮下女。

這一切都是你留給我的信物。

時不可兮再得,

難道那往昔的時光不可再得,

聊逍遙兮容與。

暫且慢步洲頭排除心中煩惱。

賞析

在屈原根據楚地民間祭神曲創作的《九歌》中,《湘君》和《湘夫人》是兩首最富生活情趣和浪漫色彩的作品。人們在欣賞和贊嘆它們獨特的南國風情和動人的藝術魅力時,卻對湘君和湘夫人的實際身份迷惑不解,進行了長時間的探討、爭論。

從有關的先秦古籍來看,盡管《楚辭》的《遠游》篇中提到“二女”和“湘靈”,《山海經·中山經》中說“洞庭之山……帝之二女居之,是常游于江淵”,但都沒有像后來的注釋把湘君指為南巡道死的舜、把湘夫人說成追趕他而溺死湘水的二妃娥皇和女英的跡象。最初把兩者結合在一起的是《史記·秦始皇本紀》。書中記載秦始皇巡游至湘山(即今洞庭湖君山)時,“上問博士曰:‘湘君何神?’博士對曰:‘聞之,堯女,舜之妻,而葬此。’”后來劉向的《列女傳》也說舜“二妃死于江、湘之間,俗謂之湘君”。這就明確指出湘君就是舜的兩個妃子,但未涉及湘夫人。到了東漢王逸為《楚辭》作注時,鑒于二妃是女性,只適合于湘夫人,于是便把湘君另指為“湘水之神”。對于這種解釋。唐代韓愈并不滿意,他在《黃陵廟碑》中認為湘君是娥皇,因為是正妃故得稱“君”;女英是次妃,因稱“夫人”。以后宋代洪興祖《楚辭補注》、朱熹《楚辭集注》皆從其說。這一說法的優點在于把湘君和湘夫人分屬兩人,雖避免了以湘夫人兼指二妃的麻煩,但仍沒有解決兩人的性別差異,從而為詮釋作品中顯而易見的男女相戀之情留下了困難。有鑒于此,明末清初的王夫之在《楚辭通釋》中采取了比較通脫的說法,即把湘君說成是湘水之神,把湘夫人說成是他的配偶,而不再拘泥于按舜與二妃的傳說一一指實。應該說這樣的理解,比較符合作品的實際,因而也比較可取。

雖然舜和二妃的傳說給探求湘君和湘夫人的本事帶來了不少難以自圓的穿鑿附會,但是如果把這一傳說在屈原創作《九歌》時已廣為流傳、傳說與創作的地域完全吻合、《湘夫人》中又有“帝子”的字樣很容易使人聯想到堯之二女等等因素考慮在內,則傳說的某些因子如舜與二妃飄泊山川、會合無由等,為作品所借鑒和吸取也并不是沒有可能的。因此既注意到傳說對作品可能產生的影響,又不拘泥于傳說的具體人事,應該成為我們理解和欣賞這兩篇作品的基點。

由此出發,不難看出作為祭神歌曲,《湘君》和《湘夫人》是一個前后相連的整體,甚至可以看作同一樂章的兩個部分。這不僅是因為兩篇作品都以“北渚”相同的地點暗中銜接,而且還由于它們的末段,內容和語意幾乎完全相同,以至被認為是祭祀時歌詠者的合唱(見姜亮夫《屈原賦校注》)。

這首《湘君》由女神的扮演者演唱,表達了因男神未能如約前來而產生的失望、懷疑、哀傷、埋怨的復雜感情。第一段寫美麗的湘夫人在作了一番精心的打扮后,乘著小船興致勃勃地來到與湘君約會的地點,可是卻不見湘君前來,于是在失望中抑郁地吹起了哀怨的排簫。首二句以問句出之,一上來就用心中的懷疑揭出愛而不見的事實,為整首歌的抒情作了明確的鋪墊。以下二句說為了這次約會,她曾進行了認真的準備,把本已姣好的姿容修飾得恰到好處,然后才駕舟而來。這說明她十分看重這個見面的機會,內心對湘君充滿了愛戀。正是在這種心理的支配下,她甚至虔誠地祈禱沅湘的江水風平浪靜,能使湘君順利赴約。然而久望之下,仍不見他到來,便只能吹起聲聲幽咽的排簫,來傾吐對湘君的無限思念。這一段的描述,讓人看到了一幅望斷秋水的佳人圖。

第二段接寫湘君久等不至,湘夫人便駕著輕舟向北往洞庭湖去尋找,忙碌地奔波在湖中江岸,結果依然不見湘君的蹤影。作品在這里把對湘夫人四出尋找的行程和她的內心感受緊密地結合在一起。你看她先是駕著龍舟北出湘浦,轉道洞庭,這時她顯然對找到湘君滿懷希望;可是除了眼前浩渺的湖水和裝飾精美的小船外,一無所見;她失望之余仍不甘心,于是放眼遠眺涔陽,企盼能捕捉到湘君的行蹤;然而這一切都毫無結果,她的心靈便再次橫越大江,遍尋沅湘一帶的廣大水域,最終還是沒有找到。如此深情的企盼和如此執著的追求,使得身邊的侍女也為她嘆息起來。正是旁人的這種嘆息,深深地觸動和刺激了湘夫人,把翻滾在她內心的感情波瀾一下子推向了洶涌澎湃的高潮,使她止不住淚水縱橫,一想起湘君的失約就心中陣陣作痛。

第三段主要是失望至極的怨恨之情的直接宣泄。首二句寫湘夫人經多方努力不見湘君之后,仍漫無目的地泛舟水中,那如劃開冰雪的船槳雖然還在擺動,但給人的感覺只是她行動的遲緩沉重和機械重復。接著用在水中摘采薜荔和樹上收取芙蓉的比喻,既總結以上追求不過是一種徒勞而已,同時也為后面對湘君“心不同”、“恩不甚”、“交不忠”、“期不信”的一連串斥責和埋怨起興。

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論