<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                上一篇文章[帶你玩轉Visual Studio——帶你跳出坑爹的Runtime Library坑](http://blog.csdn.net/luoweifu/article/details/49055933#comments)幫我們理解了Windows中的各種類型C/C++運行時庫及它的來龍去脈,這是C++開發中特別容易誤入歧途的一個地方,我們對它進行了總結和歸納。本篇文章我們將繼續講解C++開發中容易混淆的另一個概念——多字節字符集與Unicode字符集。 # 多字節字符與寬字節字符 ## char與wchar_t 我們知道C++基本數據類型中表示字符的有兩種:char、wchar_t。? char叫**多字節字符**,一個char占一個字節,之所以叫多字節字符是因為它表示一個**字**時可能是一個字節也可能是多個字節。一個英文字符(如’s’)用一個char(一個字節)表示,一個中文漢字(如’中’)用3個char(三個字節)表示,看下面的例子。 ~~~ void TestChar() { char ch1 = 's'; // 正確 cout << "ch1:" << ch1 << endl; char ch2 = '中'; // 錯誤,一個char不能完整存放一個漢字信息 cout << "ch2:" << ch2 << endl; char str[4] = "中"; //前三個字節存放漢字'中',最后一個字節存放字符串結束符\0 cout << "str:" << str << endl; //char str2[2] = "國"; // 錯誤:'str2' : array bounds overflow //cout << str2 << endl; } ~~~ 結點如下: > ch1:s? > ch2:? > str:中 wchar_t被稱為**寬字符**,一個wchar_t占2個字節。之所以叫寬字符是因為所有的字都要用兩個字節(即一個wchar_t)來表示,不管是英文還是中文。看下面的例子: ~~~ void TestWchar_t() { wcout.imbue(locale("chs")); // 將wcout的本地化語言設置為中文 wchar_t wch1 = L's'; // 正確 wcout << "wch1:" << wch1 << endl; wchar_t wch2 = L'中'; // 正確,一個漢字用一個wchar_t表示 wcout << "wch2:" << wch2 << endl; wchar_t wstr[2] = L"中"; // 前兩個字節(前一個wchar_t)存放漢字'中',最后兩個字節(后一個wchar_t)存放字符串結束符\0 wcout << "wstr:" << wstr << endl; wchar_t wstr2[3] = L"中國"; wcout << "wstr2:" << wstr2 << endl; } ~~~ 結果如下: > ch1:s? > ch2:中? > str:中? > str2:中國 **說明:**? 1\. 用常量字符給wchar_t變量賦值時,前面要加L。如: wchar_t wch2 = L’中’;? 2\. 用常量字符串給wchar_t數組賦值時,前面要加L。如: wchar_t wstr2[3] = L”中國”;? 3\. 如果不加L,對于英文可以正常,但對于非英文(如中文)會出錯。 ## string與wstring 字符數組可以表示一個字符串,但它是一個定長的字符串,我們在使用之前必須知道這個數組的長度。為方便字符串的操作,STL為我們定義好了字符串的類string和wstring。大家對string肯定不陌生,但wstring可能就用的少了。 string是普通的多字節版本,是基于char的,對char數組進行的一種封裝。 wstring是Unicode版本,是基于wchar_t的,對wchar_t數組進行的一種封裝。 ### string 與 wstring的相關轉換: 以下的兩個方法是跨平臺的,可在Windows下使用,也可在Linux下使用。 ~~~ #include <cstdlib> #include <string.h> #include <string> // wstring => string std::string WString2String(const std::wstring& ws) { std::string strLocale = setlocale(LC_ALL, ""); const wchar_t* wchSrc = ws.c_str(); size_t nDestSize = wcstombs(NULL, wchSrc, 0) + 1; char *chDest = new char[nDestSize]; memset(chDest,0,nDestSize); wcstombs(chDest,wchSrc,nDestSize); std::string strResult = chDest; delete []chDest; setlocale(LC_ALL, strLocale.c_str()); return strResult; } // string => wstring std::wstring String2WString(const std::string& s) { std::string strLocale = setlocale(LC_ALL, ""); const char* chSrc = s.c_str(); size_t nDestSize = mbstowcs(NULL, chSrc, 0) + 1; wchar_t* wchDest = new wchar_t[nDestSize]; wmemset(wchDest, 0, nDestSize); mbstowcs(wchDest,chSrc,nDestSize); std::wstring wstrResult = wchDest; delete []wchDest; setlocale(LC_ALL, strLocale.c_str()); return wstrResult; } ~~~ # 字符集(Charcater Set)與字符編碼(Encoding) **字符集(Charcater Set或Charset):**是一個系統支持的所有抽象字符的集合,也就是一系列字符的集合。字符是各種文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數字等。常見的字符集有:ASCII字符集、GB2312字符集(主要用于處理中文漢字)、GBK字符集(主要用于處理中文漢字)、Unicode字符集等。 **字符編碼(Character Encoding):**是一套法則,使用該法則能夠對自然語言的字符的一個字符集(如字母表或音節表),與計算機能識別的二進制數字進行配對。即它能在符號集合與數字系統之間建立對應關系,是信息處理的一項基本技術。通常人們用符號集合(一般情況下就是文字)來表達信息,而計算機的信息處理系統則是以二進制的數字來存儲和處理信息的。字符編碼就是將符號轉換為計算機能識別的二進制編碼。 一般一個字符集等同于一個編碼方式,ANSI體系(ANSI是一種字符代碼,為使計算機支持更多語言,通常使用 0x80~0xFF 范圍的 2 個字節來表示 1 個字符)的字符集如ASCII、ISO 8859-1、GB2312、GBK等等都是如此。一般我們說一種編碼都是針對某一特定的字符集。? 一個字符集上也可以有多種編碼方式,例如UCS字符集(也是Unicode使用的字符集)上有UTF-8、UTF-16、UTF-32等編碼方式。 從計算機字符編碼的發展歷史角度來看,大概經歷了三個階段:? 第一個階段:ASCII字符集和ASCII編碼。? 計算機剛開始只支持英語(即拉丁字符),其它語言不能夠在計算機上存儲和顯示。ASCII用一個字節(Byte)的7位(bit)表示一個字符,第一位置0。后來為了表示更多的歐洲常用字符又對ASCII進行了擴展,又有了EASCII,EASCII用8位表示一個字符,使它能多表示128個字符,支持了部分西歐字符。 第二個階段:ANSI編碼(本地化)? 為使計算機支持更多語言,通常使用 0x80~0xFF 范圍的 2 個字節來表示 1 個字符。比如:漢字 ‘中’ 在中文操作系統中,使用 [0xD6,0xD0] 這兩個字節存儲。? 不同的國家和地區制定了不同的標準,由此產生了 GB2312, BIG5, JIS 等各自的編碼標準。這些使用 2 個字節來代表一個字符的各種漢字延伸編碼方式,稱為 ANSI 編碼。在簡體中文系統下,ANSI 編碼代表 GB2312 編碼,在日文操作系統下,ANSI 編碼代表 JIS 編碼。? 不同 ANSI 編碼之間互不兼容,當信息在國際間交流時,無法將屬于兩種語言的文字,存儲在同一段 ANSI 編碼的文本中。 第三個階段:UNICODE(國際化)? 為了使國際間信息交流更加方便,國際組織制定了 UNICODE 字符集,為各種語言中的每一個字符設定了統一并且唯一的數字編號,以滿足跨語言、跨平臺進行文本轉換、處理的要求。UNICODE 常見的有三種編碼方式:UTF-8(1個字節表示)、UTF-16((2個字節表示))、UTF-32(4個字節表示)。 我們可以用一個樹狀圖來表示由ASCII發展而來的各個字符集和編碼的分支:? ![](https://box.kancloud.cn/2016-01-19_569dd03be61c3.jpg)? 圖 1: 各種類型的編譯 如果要更詳細地了解字符集和字符編碼請參考:? [字符集和字符編碼(Charset & Encoding)](http://blog.csdn.net/luoweifu/article/details/49385121) # 工程里多字節與寬字符的配制 右鍵你的工程名->Properties,設置如下:? ![](https://box.kancloud.cn/2016-01-19_569dd03c07b6b.jpg)? 圖 2: Character Set 1. 當設置為Use Unicode Character Set時,會有預編譯宏:_UNICODE、UNICODE? ![](https://box.kancloud.cn/2016-01-19_569dd03c19657.jpg) 圖 3: Unicode 2. 當設置為Use Multi-Byte Character Set時,會有預編譯宏:_MBCS? ![](https://box.kancloud.cn/2016-01-19_569dd03c2dc57.jpg) 圖 4: Multi-Byte ## Unicode Character Set與Multi-Byte Character Set有什么區別呢? Unicode Character Set和Multi-Byte Character Set這兩個設置有什么區別呢?我們來看一個例子:? 有一個程序需要用MessageBox彈出提示框: ~~~ #include "windows.h" void TestMessageBox() { ::MessageBox(NULL, "這是一個測試程序!", "Title", MB_OK); } ~~~ 上面這個Demo非常簡單不用多說了吧!我們將Character Set設置為Multi-Byte Character Set時,可以正常編譯和運行。但當我們設置為Unicode Character Set,則會有以下編譯錯誤: > error C2664: ‘MessageBoxW’ : cannot convert parameter 2 from ‘const char [18]’ to ‘LPCWSTR’ 這是因為MessageBox有兩個版本,一個MessageBoxW針對Unicode版的,一個是MessageBoxA針對Multi-Byte的,它們通過不同宏進行隔開,預設不同的宏會使用不同的版本。我們使用了Use Unicode Character Set就預設了_UNICODE、UNICODE宏,所以編譯時就會使用MessageBoxW,這時我們傳入多字節常量字符串肯定會有問題,而應該傳入寬符的字符串,即將”Title”改為L”Title”就可以了,”這是一個測試程序!”也一樣。 ~~~ WINUSERAPI int WINAPI MessageBoxA( __in_opt HWND hWnd, __in_opt LPCSTR lpText, __in_opt LPCSTR lpCaption, __in UINT uType); WINUSERAPI int WINAPI MessageBoxW( __in_opt HWND hWnd, __in_opt LPCWSTR lpText, __in_opt LPCWSTR lpCaption, __in UINT uType); #ifdef UNICODE #define MessageBox MessageBoxW #else #define MessageBox MessageBoxA #endif // !UNICODE ~~~ 上面的Multi-Byte Character Set一般是指ANSI(多字節)字符集,關于ANSI請參考第二小節[字符集(Charcater Set)與字符編碼(Encoding)](http://blog.csdn.net/luoweifu/article/details/49382969#t4)。而Unicode Character Set就是Unicode字符集,一般是指UTF-16編碼的Unicode。也就是說每個字符編碼為兩個字節,兩個字節可以表示65535個字符,65535個字符可以表示世界上大部分的語言。 一般推薦使用Unicode的方式,因為它可以適應各個國家語言,在進行軟件國際時將會非常便得。除非在對存儲要求非常高的時候,或要兼容C的代碼時,我們才會使用多字節的方式 。 # 理解_T()、_Text()宏即L”“ [上一小節](http://blog.csdn.net/luoweifu/article/details/49382969#t6)對MessageBox的調用中除了使用L”Title”外,還可以使用_T(“Title”)和_TEXT(“Title”)。而且你會發現在MFC和Win32程序中會更多地使用_T和_TEXT,那_T、_TEXT和L之間有什么區別呢? 通過第一小節[多字節字符與寬字節字符](http://blog.csdn.net/luoweifu/article/details/49382969#t0)我們知道表示多字節字符(char)串常量時用一般的雙引號括起來就可以了,如”String test”;而表示寬字節字符(wchar_t)串常量時要在引號前加L,如L”String test”。 查看tchar.h頭文件的定義我們知道_T和_TEXT的功能是一樣的,是一個預定義的宏。 ~~~ #define _T(x) __T(x) #define _TEXT(x) __T(x) ~~~ 我們再看看__T(x)的定義,發現它有兩個: ~~~ #ifdef _UNICODE // ... 省略其它代碼 #define __T(x) L ## x // ... 省略其它代碼 #else /* ndef _UNICODE */ // ... 省略其它代碼 #define __T(x) x // ... 省略其它代碼 #endif /* _UNICODE */ ~~~ 這下明白了嗎?當我們的工程的Character Set設置為Use Unicode Character Set時_T和_TEXT就會在常量字符串前面加L,否則(即Use Multi-Byte Character Set時)就會以一般的字符串處理。 ?# Dword、LPSTR、LPWSTR、LPCSTR、LPCWSTR、LPTSTR、LPCTSTR VC++中還有一些常用的宏你也許會范糊涂,如Dword、LPSTR、LPWSTR、LPCSTR、LPCWSTR、LPTSTR、LPCTSTR。這里我們統一總結一下: **常見的宏:** | 類型 | MBCS | UNICODE | | --- | --- | --- | | WCHAR | wchar_t | wchar_t | | LPSTR | char* | char* | | LPCSTR | const char* | const char* | | LPWSTR | wchar_t* | wchar_t* | | LPCWSTR | const wchar_t* | const wchar_t* | | TCHAR | char | wchar_t | | LPTSTR | TCHAR*(或char*) | TCHAR* (或wchar_t*) | | LPCTSTR | const TCHAR* | const TCHAR* | * * * **相互轉換方法:**? LPWSTR->LPTSTR: W2T();? LPTSTR->LPWSTR: T2W();? LPCWSTR->LPCSTR: W2CT();? LPCSTR->LPCWSTR: T2CW(); ANSI->UNICODE: A2W();? UNICODE->ANSI: W2A(); * * * **字符串函數:**? 還有一些字符串的操作函數,它們也有一 一對應關系: | MBCS | UNICODE | | --- | --- | | strlen(); | wcslen(); | | strcpy(); | wcscpy(); | | strcmp(); | wcscmp(); | | strcat(); | wcscat(); | | strchr(); | wcschr(); | | … | … | 通過這些函數和宏的命名你也許就發現了一些霍規律,一般帶有前綴w(或后綴W)的都是用于寬字符的,而不帶前綴w(或帶有后綴A)的一般是用于多字節字符的。 # 理解CString產生的原因與工作的機理 CString:動態的TCHAR數組,是對TCHAR數組的一種封閉。它是一個完全獨立的類,封裝了“+”等操作符和字符串操作方法,換句話說就是CString是對TCHAR操作的方法的集合。它的作用是方便WIN32程序和MFC程序進行字符串的處理和類型的轉換。 關于CString更詳細的用法請參考:? [CString與string、char*的區別和轉換](http://blog.csdn.net/luoweifu/article/details/20232379)? [CString的常見用法](http://www.cnblogs.com/Caiqinghua/archive/2009/02/16/1391190.html) * * * * * * 參考文章:? [字符集和字符編碼(Charset & Encoding)](http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html)? [字符,字節和編碼](http://www.regexlab.com/zh/encoding.htm)? [《windows核心編程系列》二談談ANSI和Unicode字符集](http://blog.csdn.net/ithzhang/article/details/7916732)? [Dword、LPSTR、LPWSTR、LPCSTR、LPCWSTR、LPTSTR、LPCTSTR](http://www.cnblogs.com/goed/archive/2011/11/11/2245702.html) 上一篇回顧:? [帶你玩轉Visual Studio——帶你跳出坑爹的Runtime Library坑](http://blog.csdn.net/luoweifu/article/details/49055933#comments) 下一篇要講述的內容:? 帶你玩轉Visual Studio——帶你解讀__cdecl、__fastcall、__stdcall三種調用約定
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看