在計算機中字符通常並不是保存為圖像,每個字符都是使用一個編碼來表示的,而每個字符究竟使用哪個編碼代表,要取決於使用哪個字符集(charset)。
多字節字符集:
在最初的時候,Internet上只有一種字符集——ANSI的ASCII字符集,它使用7 bits來表示一個 字符,總共表示128個字符,其中包括了 英文字母、數字、標點符號等常用字符。之后,又進行擴展,使用8 bits表示一個字符,可以表示256個字符,主要在原來的7 bits字符集的基礎上加入了一些特殊符號。后來,由於各國語言的加入,ASCII已經不能滿足信息交流的需要,為了能夠表示其它國家的文字,各國在 ASCII的基礎上制定了自己的字符集,這些從ANSI標准派生的字符集被習慣的統稱為ANSI字符集,它們正式的名稱應該是MBCS(Multi-Byte Chactacter System,即多字節字符系統)。這些派生字符集的特點是以ASCII 127 bits為基礎,兼容ASCII 127,他們使用大於128的編碼作為一個Leading Byte,緊跟在Leading Byte后的第二(甚至第三)個字符與 Leading Byte一起作為實際的編碼。這樣的字符集有很多,我們常見的GB-2312就是其中之一。
Unicode字符集:
Unicode的學名 是"Universal Multiple-Octet Coded Character Set",簡稱為UCS。UCS可以看作是"Unicode Character Set"的縮寫。UCS只是規定如何編碼,並沒有規定如何傳輸、保存這個編碼。UTF是“UCS Transformation Format”的縮寫。
Unicode字符集有多種編碼形式,它固定使用16 bits(兩個字節、一個字)來表示一個字符,共可以表示65536個字符。將世界上幾乎所有語言的常用字符收錄其中,方便了信息交流。標准的Unicode稱為UTF-16。后來為了雙字節的Unicode能夠在現存的處理單字節的系統上正確傳輸,出現了UTF-8(注意UTF-8是編碼,它屬於Unicode字符集),使用類似MBCS的方式對Unicode進行編碼。UTF-8以字節為編碼單元,沒有字節序的問題。UTF-16以兩個字節為編碼單元。
UTF-16包括三種:UTF-16,UTF-16BE(Big Endian),UTF-16LE(Little Endian),UTF-16需要通過在文件開頭以名為BOM(Byte Order Mark)的字符來表明文件是Big Endian還是Little Endian。Unicode規范中推薦的標記字節順序的方法是BOM(Byte Order Mark)。在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應該出現在實際傳輸中。UCS規范建議我們在傳輸字節流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。這樣如果接收者收到FEFF,就表明這個字節流是Big-Endian的;如果收到FFFE,就表明這個字節流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。
UTF-8不需要BOM來表明字節順序,但可以用BOM來表明編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者可以用我們前面介紹的編碼方法驗證一下)。所以如果接收者收到以EF BB BF開頭的字節流,就知道這是UTF-8編碼了。
Windows就是使用BOM來標記文本文件的編碼方式的。
L是用來標志一個字符(串)為寬字符(串),當你在VS2005以上版本的IDE工作時,可以選擇工作於這兩種不同的編碼方式下,而在Unicode方式下,則要對字符(串)常量前添加L來告訴編譯器它是寬字符。MS為我們定義了好幾個相關的宏:_T(定義於tchar.h)、_TEXT(同樣定義於tchar.h)。
// MessageBox("Test"); //錯誤 // MessageBox(_T("Test")); // MessageBox(TEXT("Test")); MessageBox(_TEXT("Test"));
對於為什么使用Unicode?(以下引自《windows核心編程》)
開發應用程序的時候,強烈建議你使用Unicode字符和字符串,理由如下:
- Unicode使程序的本地化變得更容易;
- 使用Unicode,只需發布一個二進制(.exe或DLL)文件,即可支持所有語言;
- Unicode代碼執行速度更快,占用內存更少,提升了應用程序的效率。自從Windows2K開始,Win的系統內核開始完全支持並完全應用Unicode編寫,所有ANSI字符在進入底層前,都會被相應的API轉換成Unicode。所以,如果你一開始就使用Unicode,則可以減少轉換的用時和RAM開銷。
- 使用Unicode,你的應用程序能輕松調用所有不反對使用(nondeprecated)的Windows函數,因為一些Windows函數提供了只能處理Unicode字符和字符串的版本;
- 使用Unicode,你的代碼很容易與COM集成(后者要求使用Unicode字符和字符串);
- 使用Unicode,你的代碼很容易與.NET Framework集成(后者要要求使用Unicode字符和字符串);
- 使用Unicode,能保證你的代碼能夠輕松操縱你自己的資源(其中的字符串總是Unicode的);
- 世界上大多數程序用的字符集都是Unicode,因為Unicode有利於程序國際化和標准化;
wchar_t與char類型間的轉換:
#include<iostream> #include<Windows.h> using namespace std; class CUser { public: CUser(); virtual ~CUser(); char* WcharToChar(wchar_t* wc);//寬字節轉單字節 wchar_t* CharToWchar(char* c); //單字節轉寬字節 void Release();//釋放資源 private: char* m_char; wchar_t* m_wchar; }; ///////////////////////////////////////////////////////////////////////////////////// /*字符類型 wchar_t char /*獲取字符長度 wcslen() strlen() /*連接兩個字符串 wcscat() strcpy() /*復制字符串 wcscpy() strcpy() /*比較兩個字符串 wcscmp() strcmp() /*具體參數詳見www.linuxidc.com*/ //////////////////////////////////////////////////////////////////////////////////// CUser::CUser():m_char(NULL),m_wchar(NULL) { } CUser::~CUser() { Release(); } //寬字節轉單字節 char* CUser::WcharToChar(wchar_t* wc) { Release(); int len= WideCharToMultiByte(CP_ACP,0,wc,wcslen(wc),NULL,0,NULL,NULL); m_char=new char[len+1]; WideCharToMultiByte(CP_ACP,0,wc,wcslen(wc),m_char,len,NULL,NULL); m_char[len]='\0'; return m_char; } //單字節轉寬字節 wchar_t* CUser::CharToWchar(char* c) { Release(); int len = MultiByteToWideChar(CP_ACP,0,c,strlen(c),NULL,0); m_wchar=new wchar_t[len+1]; MultiByteToWideChar(CP_ACP,0,c,strlen(c),m_wchar,len); m_wchar[len]='\0'; return m_wchar; } //釋放資源 void CUser::Release() { if(m_char) { delete m_char; m_char=NULL; } if(m_wchar) { delete m_wchar; m_wchar=NULL; } }
使用如下:
WCHAR* wc; CUser u; char* c=u.WcharToChar(wc); cout<<c<<endl;