windows下寬字節和多字節的問題

寬字節和多字節,一度是我的噩夢,明明是調用同一個API,但是最後的返回值一會是char *,一會又是wchar_t *,實屬煩人,前幾天看呂鑫老師的視頻,終於弄清楚了。

Windows中有兩種編碼格式:
(1) ANSI/多字節編碼(每個字符佔一個字節);
(2) UNICODE/寬字節編碼(每個字符佔兩個字節)。
(ANSI是早期的編碼格式,各國不統一,所以多種文字一起使用時經常出現亂碼,後來爲了統一編碼格式,就出現了UNICODE,所以現在項目裏默認編碼一般都推薦使用UNICODE)

正因爲上述原因,所以windows的IDE中很多API都有兩種重定義格式:
#ifdef UNICODE
#define XXX XXXW //若編碼格式爲UNICODE,則使用寬字節形式API,後綴加上W
#else
#define XXX XXXA //若編碼格式爲ANSI,則使用多字節形式API,後綴加上A
#endif

那麼問題也來了:
ANSI使用的字符串是多字節,類型定義爲const char */LPCSTR;
UNICODE使用的字符串是寬字節,類型定義爲const wchar_t */LPCWSTR;
假如項目代碼中用到了很多的字符串操作,後面萬一我想從ANSI碼切換到UNICODE碼,那麼我的字符串格式肯定也要變了,我要把每一個LPCSTR都改成LPCWSTR嗎?
或者我從UNICODE切換到ANSI,是不是也要把所有的字符串改掉?

爲了省事,windows平臺IDE給了L(X)宏和T(X)宏(頭文件:#include <tchar.h>),作用如下:
(1) L(X):把字符串X全部轉成寬字節;(這麼做有風險,假如字符集是ANSI,那麼使用L全部轉成寬字節還是會報錯)
(2) _T(X):這個宏不會明確指出到底是用ANSI還是UNICODE,它是根據API實際使用的字符集去自動轉化編碼,假如需要使用的字符串是多字節,它會把X自動轉成多字節,同理,假如需要使用的字符串是寬字節,它會把X自動轉成寬字節,比較方便,推薦使用這個宏。

此外,還有一種字符串定義方式TCHAR:
(1) Unicode模式下:TCHAR就是wchar_t;
(2) ANSI模式下:TCHAR就是char。
所以,在windows平臺IDE中,最穩如老狗的字符串定義爲: TCHAR *str = _T(“hello”);

綜上所述,我相信很多人剛寫MFC都碰到過這麼一個問題:MFC的CString字符串怎麼轉化成C語言/C++自帶的const char *類型字符串?
網上很多代碼都是類似於以下代碼寫的:

CString str = _T("Hello world!");
const char *msg = str.GetBuffer();

我把這代碼直接複製粘貼下來,但是我相信很多人又碰到了跟我一樣的問題:這個代碼,有時可以編譯通過,有時編譯卻又通不過(肯定不止我一個人碰到這個事吧),但凡是做過項目開發的都應該有這個意識,這代碼肯定是有問題的。。。。其實就是字符集在搗鬼。因爲CString類的GetBuffer()方法,返回的字符串類型就是會根據字符集自動轉換成char *(ANSI碼格式)和wchar_t *(UNICODE碼格式),所以上面兩行代碼在ANSI碼格式下不會報錯,因爲它返回的是char *多字節字符串,但是在UNICODE碼格式下肯定會報錯,因爲此時它返回的是wchar_t *寬字節字符串,下面這麼寫就比較穩妥:

CString str = _T("Hello world!");
const char *msg = (char *)str.GetBuffer();//即使返回值是wchar_t *寬字節字符串,手動強制轉換成char *

當然了,如果不嫌麻煩,最最最穩如老狗的方法還是我在上面說的TCHAR *類型字符串:

CString str = _T("Hello world!");
TCHAR *msg = str.GetBuffer();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章