CString與LPCWSTR、LPWSTR等資料型別的轉換
阿新 • • 發佈:2019-01-23
CString與LPCWSTR、LPWSTR等資料型別的轉化
之前我遇到過類似的問題,在以前兩篇博文中也提到過類似編碼問題:,但是都沒有涉及到這些資料型別的轉換。
1. CString與LPCWSTR的轉換
LPCWSTR 是Unicode字串常量指標,初始化時串有多大,申請空間就有多大,以後儲存若超過則出現無法預料的結果,這是它與CString的不同之處。而CString是一個串類,記憶體空間類會自動管理。LPCWSTR的定義為:typedef CONST WCHAR *LPCWSTR, *PCWSTR;
LPCWSTR 初始化如下:由於LPCWSTR必須指向Unicode的字串,問題的關鍵變成了ANSI字元與Unicode(可以參考:VC中_T("")與L區別)字元之間的轉換。通過查詢資料,涉及到不同編碼間的轉換,可以ATL中轉換巨集可以用如下方法實現:LPCWSTR Name=L"TestlpCwstr";
//方法一
CString str=_T("TestStr");
USES_CONVERSION;
LPWSTR pwStr=new wchar_t[str.GetLength()+1];
wcscpy(pwStr,T2W((LPCTSTR)str));
這裡兩種方法都用到了:USES_CONVERSION,它表示用來定義一些中間變數,在使用ATL的轉換巨集之前必須定義該語句。它需要包含標頭檔案:#include <atlconv.h>。 注意:慎用USES_CONVERSION USES_CONVERSION是ATL中的一個巨集定義。用於編碼轉換(用的比較多的是CString向LPCWSTR轉換)。在ATL下使用要包含標頭檔案#include <atlconv.h>// 方法二 CString str=_T("TestStr"); USES_CONVERSION; LPWCSTR pwcStr = A2CW((LPCSTR)str);
使用USES_CONVERSION一定要小心,它們從堆疊上分配記憶體,直到呼叫它的函式返回,該記憶體不會被釋放。如果在一個迴圈中,這個巨集被反覆呼叫幾萬次,將不可避免的產生stackoverflow。
在一個函式的迴圈體中使用A2W等字元轉換巨集可能引起棧溢位。
它的巨集定義為:#include <atlconv.h> void fn() { while(true) { { USES_CONVERSION; DoSomething(A2W("SomeString")); } } }
#define A2W(lpa) (\
((_lpa = lpa) == NULL) ? NULL : (\
_convert = (lstrlenA(_lpa)+1),\
ATLA2WHELPER((LPWSTR) alloca(_convert*2), _lpa, _convert)))
#define ATLA2WHELPER AtlA2WHelper
inline LPWSTR WINAPI AtlA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars, UINT acp)
{
ATLASSERT(lpa != NULL);
ATLASSERT(lpw != NULL);
// verify that no illegal character present
// since lpw was allocated based on the size of lpa
// don't worry about the number of chars
lpw[0] = '\0';
MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars);
return lpw;
}
關鍵的地方在 alloca 記憶體分配記憶體上。分配的記憶體是在函式的棧中分配的。而VC編譯器預設的棧記憶體空間是2M。當在一個函式中迴圈呼叫它時就會不斷的分配棧中的記憶體。那麼為了避免這類問題的發生,我們應該把字元轉換部分放到一個函式中處理,如下:
void fn2()
{
USES_CONVERSION;
DoSomething(A2W("SomeString"));
}
void fn()
{
while(true)
{
fn2();
}
}
如果不知道這點問題,在使用後崩潰時很難查出崩潰原因的。以上說明是為了解釋USES_CONVERSION 提供另一種快捷的方法CString中的一個方法AllocSysString,它返回BSTR
//方法三
CString str = _T("test");
LPCWSTR lpcwStr = str.AllocSysString();
如果將LPCWSTR轉換成CString,那就更加容易,在msdn中的CString類說明中提到了可以直接用LPCWSTR來構造CString,所以可以進行如下的轉換程式碼:LPCWSTR pcwStr = L"TestpwcStr";
CString str(pcwStr);
MFC中CString和LPSTR是可以通用,其中A2CW表示(LPCSTR) -> (LPCWSTR)2. CString和LPWSTR的轉換
我也看到CString和LPWSTR有這麼轉化的:CString str = _T("test");
LPWSTR lpwStr = (LPWSTR)(LPCTSTR)str;
這裡轉化以後只是得到的是一個指標,而不是str的真實內容。如果要獲取str裡面的內容,用ATL轉換如下,也有其他轉換方法:
CString str = _T("test");
USES_CONVERSION;
LPWSTR lpwStr = A2W(str);
這樣的轉換也比較簡單。。。。
當然也可以用如下方法,所用函式wcscpy,寬字元複製函式:
wchar_t szBuffer[100] = {0};
wcscpy(szBuffer,L"test");
LPWSTR lpwStr = szBuffer;
3. CString與LPSTR轉換
CString轉為LPSTR//方法一
CString str = _T("test");
LPSTR lpStr = str.GetBuffer();
str.ReleaseBuffer();
//方法二
CString str = _T("test");
LPSTR lpStr = (LPSTR)(LPCSTR)str;
LPSTR轉為CString這裡比較簡單,給出一種轉換方法。
LPSTR lpStr = L"lpTestStr";
CString str(lpStr);
4. CString轉為LPCSTR
CString轉為LPCSTR可直接轉換CString str = _T("test");
LPCSTR lpcStr = (LPCSTR)str;
5. CString轉為char*
//方法一
CString str = _T("test");
char *p = str.GetBuffer();
//方法二
CString str = _T("test");
char *p = (LPSTR)(LPCSTR)str;
char *轉換成CStringchar *p = "test";
CString str = ("%s",p);
或者char *p = "test";
CString str;
str.Format(_T("%s"),p);
6. CString轉換成int、float等
直接使用atoi,atof,atol等函式來實現。7. 其他型別
在標頭檔案<atlconv.h>中定義了ATL提供的所有轉換巨集,如:A2CW (LPCSTR) -> (LPCWSTR)
A2W (LPCSTR) -> (LPWSTR)
W2CA (LPCWSTR) -> (LPCSTR)
W2A (LPCWSTR) -> (LPSTR)
所有的巨集如下表所示:
A2BSTR | OLE2A | T2A | W2A |
A2COLE | OLE2BSTR | T2BSTR | W2BSTR |
A2CT | OLE2CA | T2CA | W2CA |
A2CW | OLE2CT | T2COLE | W2COLE |
A2OLE | OLE2CW | T2CW | W2CT |
A2T | OLE2T | T2OLE | W2OLE |
A2W | OLE2W | T2W | W2T |
上表中的巨集函式,非常的有規律,每個字母都有確切的含義如下:
2 | to 的發音和 2 一樣,所以借用來表示“轉換為、轉換到”的含義。 |
A | ANSI 字串,也就是 MBCS。 |
W、OLE | 寬字串,也就是 UNICODE。 |
T | 中間型別T。如果定義了 _UNICODE,則T表示W;如果定義了 _MBCS,則T表示A |
C | const 的縮寫 |
利用這些巨集,可以快速的進行各種字元間的轉換。使用前必須包含標頭檔案,並且申明USER_CONVERSION;
使用 ATL 轉換巨集,由於不用釋放臨時空間,所以使用起來非常方便。
但是考慮到棧空間的尺寸(VC 預設2M),使用時要注意幾點:
1、只適合於進行短字串的轉換;
2、不要試圖在一個次數比較多的迴圈體內進行轉換;
3、不要試圖對字元型檔案內容進行轉換,因為檔案尺寸一般情況下是比較大的;
4、對情況 2 和 3,要使用 MultiByteToWideChar() 和 WideCharToMultiByte();