windows字符類型
所謂的短字符,就是用8bit來表示的字符,典型的應用是ASCII碼.而寬字符,顧名思義,就是用16bit表示的字符,典型的有UNICODE.關於windows下的ASCII和UNICODE的更多信息,能夠參考這兩本經典著做:《windows 程序設計》,《windows 核心編程》.這兩本書關於這兩種字符都有比較詳細的解說.
寬字符轉換爲多個短字符是一個難點,不過咱們只要掌握到其中的要領,即可如魚得水.
char:
ANSI字符串,可用字符串處理函數strcat( ),strcpy( ), strlen( )等以str打頭的函數。
wchar_t :
wchar_t是Unicode字符的數據類型,它的實際定義爲:typedef unsigned short wchar_t;
wchar_t 可用字符串處理函數:wcscat(),wcscpy(),wcslen()等以wcs打頭的函數。
WCHAR:
在頭文件中有這樣的定義:typedef wchar_t WCHAR; 因此WCHAR實際就是wchar_t。
在C語言裏面提供了_UNICODE宏(有下劃線),在Windows裏面提供了UNICODE宏(無下劃線),只要定了_UNICODE宏和UNICODE宏,系統就會自動切換到UNICODE版本,不然,系統按照ANSI的方式進行編譯和運行。只定義了宏並不能實現自動的轉換,他還須要一系列的字符定義支持。
TCHAR:
若是定義了UNICODE宏則TCHAR被定義爲wchar_t。typedef wchar_t TCHAR; 不然TCHAR被定義爲char typedef char TCHAR;
ACHAR:
此類型是AUTODESK公司在adachar.h 頭文件中定義的。
當定義了AD_UNICODE(AUTODESK公司使用UNICODE宏)時爲wchar_t。
::setlocale(LC_ALL, "chs");
MultiByteToWideChar和WideCharToMultiByte用法詳解
這個是咱們須要轉化的多字節字符串:
char sText[20] = {"多字節字符串!OK!"};
咱們須要知道轉化後的寬字符須要多少個數組空間.雖然在這個里程裏面,咱們能夠直接定義一個20*2寬字符的數組,而且事實上將運行得很是輕鬆愉快.但假如多字節字符串更多,達到上千個乃至上萬個,咱們將會發現其中浪費的內存將會愈來愈多.因此以多字節字符的個數的兩倍做爲寬字符數組下標的聲明絕對不是一個好主意.
所幸,咱們可以確知所須要的數組空間.
咱們只須要將MultiByteToWideChar()的第四個形參設爲-1,便可返回所需的短字符數組空間的個數:
DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, sText, -1, NULL, 0);
接下來,咱們只須要分配響應的數組空間:
wchar_t *pwText;
pwText = new wchar_t[dwNum];
if(!pwText)
{
delete []pwText;
}
接着,咱們就能夠着手進行轉換了.在這裏以轉換成ASCII碼作爲例子:
MultiByteToWideChar (CP_ACP, 0, psText, -1, sText, dwSize);
最後,使用完畢固然要記得釋放佔用的內存:
delete []psText;
同理,寬字符轉爲多字節字符的代碼以下:
wchar_t wText[20] = {L"寬字符轉換實例!OK!"};
DWORD dwNum = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);
char *psText;
psText = new char[dwNum];
if(!psText)
{
delete []psText;
}
WideCharToMultiByte (CP_OEMCP,NULL,lpcwszStr,-1,psText,dwNum,NULL,FALSE);
delete []psText;
若是以前咱們已經分配好空間,而且因爲字符串較短,能夠不理會浪費的空間,僅僅只是想簡單地將短字符和寬字符相互轉換,那有沒有什麼簡便的方法呢?
WIN32 API裏沒有符合這種要求的函數,但咱們能夠本身進行封裝:
//-------------------------------------------------------------------------------------
//Description:
// This function maps a character string to a wide-character (Unicode) string
//
//Parameters:
// lpcszStr: [in] Pointer to the character string to be converted
// lpwszStr: [out] Pointer to a buffer that receives the translated string.
// dwSize: [in] Size of the buffer
//
//Return Values:
// TRUE: Succeed
// FALSE: Failed
//
//Example:
// MByteToWChar(szA,szW,sizeof(szW)/sizeof(szW[0]));
//---------------------------------------------------------------------------------------
BOOL MByteToWChar(LPCSTR lpcszStr, LPWSTR lpwszStr, DWORD dwSize)
{
// Get the required size of the buffer that receives the Unicode
// string.
DWORD dwMinSize;
dwMinSize = MultiByteToWideChar (CP_ACP, 0, lpcszStr, -1, NULL, 0);
if(dwSize < dwMinSize)
{
return FALSE;
}
// Convert headers from ASCII to Unicode.
MultiByteToWideChar (CP_ACP, 0, lpcszStr, -1, lpwszStr, dwMinSize);
return TRUE;
}
//-------------------------------------------------------------------------------------
//Description:
// This function maps a wide-character string to a new character string
//
//Parameters:
// lpcwszStr: [in] Pointer to the character string to be converted
// lpszStr: [out] Pointer to a buffer that receives the translated string.
// dwSize: [in] Size of the buffer
//
//Return Values:
// TRUE: Succeed
// FALSE: Failed
//
//Example:
// MByteToWChar(szW,szA,sizeof(szA)/sizeof(szA[0]));
//---------------------------------------------------------------------------------------
BOOL WCharToMByte(LPCWSTR lpcwszStr, LPSTR lpszStr, DWORD dwSize)
{
DWORD dwMinSize;
dwMinSize = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);
if(dwSize < dwMinSize)
{
return FALSE;
}
WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,lpszStr,dwSize,NULL,FALSE);
return TRUE;
}
使用方法也很簡單,示例以下:
wchar_t wText[10] = {L"函數示例"};
char sText[20]= {0};
WCharToMByte(wText,sText,sizeof(sText)/sizeof(sText[0]));
MByteToWChar(sText,wText,sizeof(wText)/sizeof(wText[0]));
這兩個函數的缺點在於沒法動態分配內存,在轉換很長的字符串時可能會浪費較多內存空間;優勢是,在不考慮浪費空間的狀況下轉換較短字符串很是方便.
2.MultiByteToWideChar()函數亂碼的問題
有的朋友可能已經發現,在標準的WinCE4.2或WinCE5.0 SDK模擬器下,這個函數都沒法正常工做,其轉換以後的字符全是亂碼.及時更改MultiByteToWideChar()參數也依然如此.
不過這個不是代碼問題,其結症在於所定製的操做系統.若是咱們定製的操做系統默認語言不是中文,也會出現這種狀況.因爲標準的SDK默認語言爲英文,因此確定會出現這個問題.而這個問題的解決,不能在簡單地更改控制面板的"區域選項"的"默認語言",而是要在系統定製的時候,選擇默認語言爲"中文".
系統定製時選擇默認語言的位置於:
Platform -> Setting... -> locale -> default language ,選擇"中文",而後編譯便可.
>>>>>History of Character Sets (from Programming Windows)
●●The American Standard Code for Information Interchange (ASCII) had its origins in the late 1950s and was finalized in 1967.
●●The final code had 26 lowercase letters, 26 uppercase letters, 10 digits, 32 symbols, 33 control codes, and a space, for a total of 128 codes.
●●The basic problem we have here is that the world's written languages simply cannot be represented by 256 8-bit codes
●●Unicode is a uniform 16-bit system, thus allowing the representation of 65,536 characters. This is sufficient for all the characters and ideographs in all the written languages of the world, including a bunch of math, symbol, and dingbat collections.
●●ANSI C supports character sets that require more than one byte per character through a concept called "wide characters."
●●Wide characters aren't necessarily Unicode. Unicode is one possible wide-character encoding.
●●Wide characters in C are based on the wchar_t data type, which is defined in several header files, including WCHAR.H, like so:
typedef unsigned short wchar_t ;
To define a variable containing a single wide character, use the following statement:
wchar_t c = `A' ;
You can also define an initialized pointer to a wide-character string:
wchar_t * p = L"Hello!" ;
Similarly, you can define an array of wide characters this way:
static wchar_t a[] = L"Hello!" ;
The string again requires 14 bytes of storage, and sizeof (a) will return 14.
●●>>>>>>>>>>win32
TCHAR.H provides a set of alternative names for the normal run-time library functions requiring string parameters (for example, _tprintf and _tcslen). These are sometimes referred to as "generic"function names because they can refer to either the Unicode or non-Unicode versions of the functions.
TCHAR.H also solves the problem of the two character data types with a new data type named TCHAR.
If the _UNICODE identifier is defined, TCHAR is wchar_t:
typedef wchar_t TCHAR ;
Otherwise, TCHAR is simply a char:
typedef char TCHAR ;
If the _UNICODE identifier is defined, a macro called __T is defined like this:
#define __T(x) L##x
If the _UNICODE identifier is not defined, the __T macro is simply defined in the following way:
#define __T(x) x
●●>>>>>>>---- arx2004
在 adesk.h 中
// Continued use of the type "char" is prohibited. Please
// use only the abstract type "ACHAR" below, to contain
// character information.
typedef char ACHAR;
●●>>>>>>>------arx2007
在 adesk.h 中,有變化
#include "AdAChar.h" // ACHAR typedef
而在adaAChar.h 中
typedef wchar_t ACHAR;
//-------------------------------------------
L與_T("")區別
VC++裏面定義字符串的時候,用_T來保證兼容性。VC++支持ascii和unicode兩種字符類型,用_T能夠保證從ascii編碼類型轉換到unicode編碼類型的時候,程序不須要修改。
若是未來你不打算升級到unicode,那麼也不須要_T。
_t("hello world")
在ansi的環境下,它是ansi的,若是在unicode下,那麼它將自動解釋爲雙字節字符串,既unicode編碼。
這樣作的好處,不論是ansi環境,仍是unicode環境,都適用。
那麼在VC++中,字符串_T("ABC")和一個普通的字符串"ABC"有什麼區別呢?
_T("ABC")
若是定義了unicode,它將表示爲L"ABC",每一個字符爲16位,寬字符串。
若是沒有定義unicode,它就是ascii的"ABC",每一個字符爲8位。
至關於
#ifdef _UNICODE
#define _T("ABC") L"ABC"
#else
#define _T("ABC") "ABC"
#endif
_T("ABC")中的一個字符和漢字同樣,佔兩個字節,而在"ABC"中,英文字符佔一個字節,漢字佔兩個字節。
1、 在字符串前加一個L做用:
如 L"個人字符串" 表示將ANSI字符串轉換成unicode的字符串,就是每一個字符佔用兩個字節。
strlen("asd") = 3;
strlen(L"asd") = 6;
2、 _T宏能夠把一個引號引發來的字符串,根據你的環境設置,使得編譯器會根據編譯目標環境選擇合適的(Unicode仍是ANSI)字符處理方式
若是你定義了UNICODE,那麼_T宏會把字符串前面加一個L。這時 _T("ABCD") 至關於 L"ABCD" ,這是寬字符串。
若是沒有定義,那麼_T宏不會在字符串前面加那個L,_T("ABCD") 就等價於 "ABCD"
3、TEXT,_TEXT 和_T 同樣的
以下面三語句:
TCHAR szStr1[] = TEXT("str1");
char szStr2[] = "str2";
WCHAR szStr3[] = L("str3");
那麼第一句話在定義了UNICODE時會解釋爲第三句話,沒有定義時就等於第二句話。
但二句話不管是否認義了UNICODE都是生成一個ANSI字符串,而第三句話老是生成UNICODE字符串。
爲了程序的可移植性,建議都用第一種表示方法。
但在某些狀況下,某個字符必須爲ANSI或UNICODE,那就用後兩種方法。
經常使用的unicode數據類型
在PPC開發中,使用的是unicode字符集,因此會常常用到一些數據類型,如下就是一些經常使用類型:
WCHAR :一個unicode字符。
LPWSTR:指向一個unicode字符的指針。
LPCWSTR:指向一個unicode字符串常量的指針。
TEXT("")和L""是windows.h中定義的宏,這兩個在使用上常常是混用的,也沒有什麼區別,可是在使用時,最好仍是用TEXT("")而不是L""。由於,L""只能生成unicode字符串,而TEXT("")與目標環境相關,在winCE下生成unicode字符串,在win9X下則生成ANSI字符串,其經常使用簡寫爲_T("")。
關於char, wchar_t, TCHAR, _T(),L,宏 _T、TEXT,_TEXT、L
char :單字節變量類型,最多表示256個字符,
wchar_t :寬字節變量類型,用於表示Unicode字符,
它實際定義在<string.h>裏:typedef unsigned short wchar_t。
爲了讓編譯器識別Unicode字符串,必須以在前面加一個「L」,定義寬字節類型方法以下:
wchar_t c = `A' ;
wchar_t * p = L"Hello!" ;
wchar_t a[] = L"Hello!" ;
其中,寬字節類型每一個變量佔用2個字節,故上述數組a的sizeof(a) = 14
TCHAR / _T( ) :
若是在程序中既包括ANSI又包括Unicode編碼,須要包括頭文件tchar.h。TCHAR是定義在該頭文件中的宏,它視你是否認義了_UNICODE宏而定義成:
定義了_UNICODE: typedef wchar_t TCHAR ;
沒有定義_UNICODE: typedef char TCHAR ;
#ifdef UNICODE
typedef char TCHAR;
#else
typede wchar_t TCHAR;
#endif
_T( )也是定義在該頭文件中的宏,視是否認義了_UNICODE宏而定義成:
定義了_UNICODE: #define _T(x) L##x
沒有定義_UNICODE: #define _T(x) x
注意:若是在程序中使用了TCHAR,那麼就不該該使用ANSI的strXXX函數或者Unicode的wcsXXX函數了,而必須使用tchar.h中定義的_tcsXXX函數。
以strcpy函數爲例子,總結一下:
Code
//若是你想使用ANSI字符串,那麼請使用這一套寫法:
char szString[100];
strcpy(szString,"test");
//若是你想使用Unicode字符串,那麼請使用這一套:
wchar_t szString[100];
wcscpy(szString,L"test");
//若是你想經過定義_UNICODE宏,而編譯ANSI或者Unicode字符串代碼:
TCHAR szString[100];
_tcscpy(szString,_TEXT("test"));
CSDN:superarhow說: 不要再使用TCHAR和_T了!他分析了緣由後總結:如 果您正開始一個新的項目,請不管如何也要頂住壓力,直接使用UNICODE編碼!切記!您只須要對您的組員進行10分鐘的培訓,記住strcpy用 wcscpy,sprintf用swprintf代替,常數前加L,就能夠了!它不會花您不少時間的,帶給您的是穩定和安全!相信偶,沒錯的!!
1、 在字符串前加一個L做用:
如 L"個人字符串" 表示將ANSI字符串轉換成unicode的字符串,就是每一個字符佔用兩個字節。
strlen("asd") = 3;
strlen(L"asd") = 6;
2、 _T宏能夠把一個引號引發來的字符串,根據你的環境設置,使得編譯器會根據編譯目標環境選擇合適的(Unicode仍是ANSI)字符處理方式
若是你定義了UNICODE,那麼_T宏會把字符串前面加一個L。這時 _T("ABCD") 至關於 L"ABCD" ,這是寬字符串。
若是沒有定義,那麼_T宏不會在字符串前面加那個L,_T("ABCD") 就等價於 "ABCD"
3、TEXT,_TEXT 和_T 同樣的
以下面三語句:
TCHAR szStr1[] = TEXT("str1");
char szStr2[] = "str2";
WCHAR szStr3[] = L("str3");
那麼第一句話在定義了UNICODE時會解釋爲第三句話,沒有定義時就等於第二句話。
但二句話不管是否認義了UNICODE都是生成一個ANSI字符串,而第三句話老是生成UNICODE字符串。
爲了程序的可移植性,建議都用第一種表示方法。
但在某些狀況下,某個字符必須爲ANSI或UNICODE,那就用後兩種方法。
4、修改字符串運算問題
一些字符串操做函數須要獲取字符串的字符數(sizeof(szBuffer)/sizeof(TCHAR)),而另外一些函數可能須要獲取字符串的字節數sizeof(szBuffer)。您應該注意該問題並仔細分析字符串操做函數,以肯定可以獲得正確的結果。
ANSI操做函數以str開頭,如strcpy(),strcat(),strlen();
Unicode操做函數以wcs開頭,如wcscpy,wcscpy(),wcslen();
MBCS 操做函數以_mbs開頭 _mbscpy
ANSI/Unicode操做函數以_tcs開頭 _tcscpy(C運行期庫); TCHAR
ANSI/Unicode操做函數以lstr開頭 lstrcpy(Windows函數);
考慮ANSI和Unicode的兼容,咱們須要使用以_tcs開頭或lstr開頭的通用字符串操做函數。
全部新的和未過期的函數在Windows2000中都同時擁有ANSI和Unicode兩個版本。ANSI版本函數結尾以A表示;Unicode版本函數結尾以W表示。Windows會以下定義:
#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif // !UNICODE
字符集 實例
ANSI 「string」
Unicode L「string」
ANSI/Unicode T(「string」)或_TEXT(「string」)if( szError[0] == _TEXT(‘J’) ){ }
5、printf和wprintf
printf("%s", "multibyte中文\n"); // ④
printf("%S", L"unicode中文\n"); // ⑤
wprintf(L"%S", "multibyte中文\n"); // ⑥
wprintf(L"%s", L"unicode中文\n"); // ⑦
缺省狀況下,⑤、⑦兩條語句不能輸出中文,這兩條語句中字符串的形式是unicode形式的。若是在全部輸出語句以前加上以下語句將C語言的全局locale設置爲本地語言(C語言中只有全局locale)就能夠正常輸出了:
setlocale(LC_CTYPE, ""); // ⑧
但這會致使cout和wcout不能輸出中文(汗,的確麻煩),將C語言的全局locale恢復後cout和wcout就正常了,以下所示:
setlocale(LC_CTYPE, "C"); // ⑨
但恢復後,printf和wprintf輸出Unicode文本又不正常了(輸出MultiByte文本老是正常的)。總不能每寫一個 printf/wprintf就設置一次而後再恢復一次吧?因此,建議不要混用iostream和printf/wprintf,實在要混用,那就讓 printf/wprintf只輸出MultiByte字符串,這樣不須要調用setlocale(),也就不會影響到cout和wcout。
若是要用wcout,須要在使用以前按語句①將其locale設置爲本地語言;
若是要用ofstream或wofstream,要在打開文件以前按語句②將全局locale設爲本地語言並保存初始的全局locale。而後在打開文件以後,按語句③將全局locale恢復爲初始值;
不要混用iostream和printf/wprintf。若是要混用,只用printf/wprintf輸出MultiByte字符串;
單獨使用printf/wprintf時,若是要輸出Unicode字符串,須要按語句⑧設置C語言的全局locale。若是隻輸出MultiByte字符串,則不需設置。ios