1. 程式人生 > >CString與LPCWSTR、LPWSTR等資料型別的轉換

CString與LPCWSTR、LPWSTR等資料型別的轉換

CString與LPCWSTR、LPWSTR等資料型別的轉化

之前我遇到過類似的問題,在以前兩篇博文中也提到過類似編碼問題:,但是都沒有涉及到這些資料型別的轉換。

1. CString與LPCWSTR的轉換

LPCWSTR 是Unicode字串常量指標,初始化時串有多大,申請空間就有多大,以後儲存若超過則出現無法預料的結果,這是它與CString的不同之處。而CString是一個串類,記憶體空間類會自動管理。LPCWSTR的定義為:
typedef CONST WCHAR *LPCWSTR, *PCWSTR;
LPCWSTR 初始化如下:
LPCWSTR Name=L"TestlpCwstr"; 
由於LPCWSTR必須指向Unicode的字串,問題的關鍵變成了ANSI字元與Unicode(可以參考:VC中_T("")與L區別)字元之間的轉換。通過查詢資料,涉及到不同編碼間的轉換,可以ATL中轉換巨集可以用如下方法實現:
//方法一 
CString str=_T("TestStr"); 
USES_CONVERSION; 
LPWSTR pwStr=new wchar_t[str.GetLength()+1]; 
wcscpy(pwStr,T2W((LPCTSTR)str));
// 方法二 
CString str=_T("TestStr"); 
USES_CONVERSION; 
LPWCSTR pwcStr = A2CW((LPCSTR)str); 
這裡兩種方法都用到了:USES_CONVERSION,它表示用來定義一些中間變數,在使用ATL的轉換巨集之前必須定義該語句。它需要包含標頭檔案:#include <atlconv.h>。 注意:慎用USES_CONVERSION USES_CONVERSION是ATL中的一個巨集定義。用於編碼轉換(用的比較多的是CString向LPCWSTR轉換)。在ATL下使用要包含標頭檔案#include <atlconv.h>
使用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 *轉換成CString
char *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();

8. 參考資料: