淺談c++字符串——3 MFC字符串

3 MFC字符串

3.1 MFC下的常用字符串數據類型表示的含義

L:Long  長  P:Point  指針  C:Const  常量  W:Wchar_t  寬字符  T:TCHAR STR:String  字符串

在看看MFC下各種數據類型的定義:

typedef char *LPSTR;typedef const char *LPCSTR;

typedef wchar_t *LPWSTR; typedef const wchar_t *LPCWSTR; typedef wchar_t WCHAR; #ifdef  UNICODE typedef  LPCWSTR  LPCTSTR; typedef  WCHAR   TCHAR;

#else typedef  LPCSTR  LPCTSTR;

typedef  char  TCHAR;

3.2 MFC下提供的ATL轉換宏(寬字節 <-> 多字節)

T2A   T2W   T2CA  T2CW         W2A   W2CA   W2T   W2CT         A2W   A2CW   A2T   A2CT 

T:TCHAR 2:To C:CONST A:CHAR(ANSI)   W:WCHAR

先到atlconv.h頭文件下看看這些宏的定義,

3.2.1 USES_CONVERSION

注意int _convert; (_convert);這種用法是爲了屏蔽編譯器的警告:未引用的局部變量。。。

#ifndef _DEBUG
#define USES_CONVERSION int _convert; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw; (_lpw); LPCSTR _lpa; (_lpa)
#else
#define USES_CONVERSION int _convert = 0; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw = NULL; (_lpw); LPCSTR _lpa = NULL; (_lpa)
#endif

可見,USES_CONVERSION宏定義了一些轉換所需要的變量,如_convert。所以使用那些宏的時候必須加上該宏。

3.2.2 以A2W爲例說明宏轉換過程

3.2.2.1 A2W多字節轉換爲寬字節

這裏就用到了USES_CONVERSION宏定義的_convert變量

#define A2W(lpa) (\
((_lpa = lpa) == NULL) ? NULL : (\
_convert = (lstrlenA(_lpa)+1),\
(INT_MAX/2<_convert)? NULL :  \
ATLA2WHELPER((LPWSTR) alloca(_convert*sizeof(WCHAR)), _lpa, _convert, _acp)))

3.2.2.2 ATLA2WHELPER 多字節轉換爲寬字節

#define ATLA2WHELPER AtlA2WHelper

AtlA2WHelper實際上還是在調用MultiByteToWideChar,即多字節轉換爲寬字節

Ret_opt_z_cap_(nChars) inline LPWSTR WINAPI AtlA2WHelper(_Out_z_cap_(nChars) LPWSTR lpw, _In_z_ LPCSTR lpa, _In_ int nChars, _In_ UINT acp) throw()
{

    ATLASSERT(lpa != NULL);
    ATLASSERT(lpw != NULL);
    if (lpw == NULL || lpa == NULL)
        return NULL;
    *lpw = '\0';
    int ret = MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars);
    if(ret == 0)
    {
        ATLASSERT(FALSE);
    return NULL;
    }  
    return lpw;
}

3.2.2.3 alloca 從堆上分配以字節爲單位的內存

#define alloca  _alloca

_alloca:該函數從堆上分配以字節爲單位的內存,返回void *

void *_alloca(
size_t size
);

3.2.2.4 用法舉例

USES_CONVERSION;//USES_CONVERSION是ATL中的一個宏定義,用於編碼轉換,它定義了轉換宏所需的一些局部變量

WCHAR *pWch = L"WCHAR* TO CHAR*";

CHAR *pCh = W2A(pWch);

TCHAR *pTch = _T("TCHAR* TO CHAR*");

CHAR *pCh2 = T2A(pTch);

3.2.3 USES_CONVERSION使用注意

使用USES_CONVERSION一定要小心,它們從堆棧上分配內存,直到調用它的函數返回,該內存不會被釋放。如果在一個循環中,這個宏被反覆調用幾萬次,將不可避免的產生stackoverflow。但是考慮到棧空間的尺寸(默認2M),使用時要注意幾點:

1、只適合於進行短字符串的轉換;

2、不要試圖在一個次數比較多的循環體內進行轉換;

3、不要試圖對字符型文件內容進行轉換,因爲文件尺寸一般情況下是比較大的;

4、對情況 2 和 3,要使用 MultiByteToWideChar() 和 WideCharToMultiByte();

5、將字符轉換封裝到函數裏面

void DoA2W()
{
     USES_CONVERSION;
     DoSomething(A2W("SomeString"));
}

3.3 CString

Header

Use for

 

cstringt.h

MFC-only string objects

必須使用在MFC程序中,需要MFC靜態或動態庫幷包含頭文件<afxwin.h>

atlstr.h

Non-MFC string objects

可以使用在非MFC程序中,只需包含<atlstr.h>非常好用,支持Unicode字符集

具體MSDN中有詳細的介紹

3.4 淺談_T、_TEXT、TEXT、L

MSDN中對於L的說明有一大堆英文,不過主要的就是:L是用來標誌一個字符(串)爲寬字符(串)

寬字符和多字節字符的說明如下:(引用自網絡)

寬字符,wide character,該字符集內每個字符使用相同的位長;

多字節字符,multibyte character,每個字符可以是一到多個字節不等,而某個字節序列的字符值由字符串或流(stream)所在的環境背景決定。

當你在VS2005以上版本的IDE工作時,可以選擇工作於這兩種不同的編碼方式下,而在Unicode方式下,則要對字符(串)常量前添加L來告訴編譯器它是寬字符

而MS爲我們定義了好幾個相關的宏,下面來一一說明:

_T            //定義於tchar.h

_TEXT      //同樣定義於tchar.h,具體如下:

#define _T(x)       __T(x)

#define _TEXT(x)    __T(x)

 

#ifdef  _UNICODE

#define __T(x)      L ## x     //第210行

#else

#define __T(x)      x          //第858行

#endif

TEXT     //定義於winnt.h

#define TEXT(quote) __TEXT(quote)

 

#ifdef  UNICODE                     

#define __TEXT(quote) L##quote      

#else   /* UNICODE */               

#define __TEXT(quote) quote         

#endif /* UNICODE */   

當我看到這裏的時候,一下子頭暈了,不知道大家有沒有注意到下面兩個問題:

1.這三個宏分別在兩個不同的文件被定義,看上去一個是運行時的頭文件,一個是Win的頭文件

2.前面兩個根據_UNICODE來確定宏內容,另一個則是根據UNICODE

那如果要同時使用這三個宏的話,那不是要同時定義_UNICODE和UNICODE?帶着問題,我把項目的屬性修改一下

當設置爲Unicode編碼的時候,編譯器命令選項中的確同時加入了_UNICODE和UNICODE

看來這應該又是MS的歷史遺留問題拉,搜索一下才發現:(引自網絡)

Jeffrey Richter在《Windows核心編程》中說,_UNICODE宏用於C運行期頭文件,而UNICODE宏則用於Windows頭文件.當編譯源代碼模塊時,通常必須同時定義這兩個宏.

看IDE自動生成的代碼,大都使用TEXT這個,應該是因爲IDE生成的都是基於Win的代碼,使用這個也很正常吧

從上面的分析可得:

這幾個宏的效果都是一個的,還是建議大家有事沒事都加上其中一個(_T、_TEXT、TEXT)

而L嘛,個人認爲還是不要在代碼中直接使用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章