• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

             

            Unicode

            ?2.8.1 C 運(yùn)行期庫對(duì)Unicode的支持

            ? 2.8.1.1 對(duì)標(biāo)準(zhǔn)的C頭文件<String.h> 作了修改,定義了一個(gè)名字為wchar_t的數(shù)據(jù)類型,用于處理Unicode 字符。

            ?????????
            typedef unsigned short wchar_t;
            ????????
            ? 2.8.1.2 添加了與ANSI C字符串對(duì)應(yīng)的字符串處理函數(shù),以wcs開頭用于處理Unicode字符。

            ????????? wchar_t * wcscat(wchar_t *,const wchar_t *);
            ????????? wchar_t * wcschr(const wchar_t *,wchar_t);
            ????????? int wcscmp(const wchar_t *,const wchar_t *);
            ????????? wchar_t * wcscpy(wchar_t *,const wchar_t *);
            ????????? size_t wcslen(const wchar_t *);


            ? 2.8.1.3 為了建立雙重功能,提供了<TChar.h>幫助創(chuàng)建ANSI/Unicode通用源代碼文件,<TChar.h>提供了一些通用宏根據(jù)是否定義了_UNICODE來判斷是使用ANSI數(shù)據(jù)類型還是Unicode數(shù)據(jù)類型,是使用ANSI字符串處理函數(shù)還是使用Unicode字符串處理函數(shù)
            ????????
            類似于"Error"這樣的字符串提供了 _T 和 _TEXT 2個(gè)通用宏。

            ???????? #ifdef _UNICODE
            ????????
            typedef wchar_t TCHAR;
            ?????? ? #else
            ?????? ?
            typedef char TCHAR; //!UNICODE

            ????????
            #ifdef _UNICODE
            ????????
            #define __T(x) L##x
            ?????? ? #else
            ?????? ?
            #define __T(x) x //!UNICODE

            ????????
            #ifdef _UNICODE
            ????????
            #define _TEXT(x) L ## x
            ?????? ? #else
            ?????? ?
            #define _TEXT(x) x //!UNICODE

            ????????
            #ifdef _UNICODE
            ????????
            #define _tcslen wcslen
            ?????? ? #else
            ?????? ?
            #define _tcslen strlen //!UNICODE


            ? 2.8.1.4
            printf函數(shù)家族是要介紹的最后一組C運(yùn)行期函數(shù)。如果在定義了_UNICODE的情況下編譯你的源代碼模塊,那么printf函數(shù)家族便希望所有字符和字符串參數(shù)代表Unicode字符和字符串。但是,如果在沒有定義_UNICODE的情況下編譯你的源代碼模塊,printf函數(shù)家族便希望傳遞給它的所有字符和字符串都是ANSI字符和字符串。但有個(gè)壞消息:在Windows程序中不能使用printf。雖然Windows程序中可以使用大多數(shù)C的執(zhí)行時(shí)期鏈接庫-實(shí)際上,許多程序?qū)懽髡吒敢馐褂肅內(nèi)存管理和文件I/O函數(shù)而不是Windows中等效的函數(shù)-Windows對(duì)標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出沒有概念。在Windows程序中可使用fprintf,而不是printf。還有一個(gè)好消息,那就是仍然可以使用sprintf及sprintf系列中的其它函數(shù)來顯示文字。這些函數(shù)除了將內(nèi)容格式化輸出到函數(shù)第一個(gè)參數(shù)所提供的字符串緩沖區(qū)以外,其功能與printf相同。

            ?2.8.3 Windows中的Unicode函數(shù)和ANSI函數(shù)


            ? 2.8.3.1
            Windows NT從底層支援Unicode。這意味著Windows NT內(nèi)部使用由16位字符組成的字符串。因?yàn)槭澜缟掀渌S多地方還不使用16位字符串,所以Windows NT必須經(jīng)常將字符串在操作系統(tǒng)內(nèi)轉(zhuǎn)換。Windows NT可執(zhí)行為ASCII、Unicode或者ASCII和Unicode混合編寫的程序。即,Windows NT支持不同的API函數(shù)呼叫,這些函數(shù)接受8位或16位的字符串.

            ? 2.8.3.2 一個(gè)Windows程序包括表頭文件WINDOWS.H。該文件包括許多其它表頭文件,包括WINDEF.H,該文件中有許多在Windows中使用的基本型態(tài)定義,而且它本身也包括WINNT.H。WINNT.H處理基本的Unicode支持。

            WINNT.H的前面包含C的表頭文件CTYPE.H,這是C的眾多表頭文件之一,包括wchar_t的定義。WINNT.H定義了新的數(shù)據(jù)型態(tài),稱作CHAR和WCHAR:

            typedef char CHAR ;        
            typedef wchar_t WCHAR ;    // wc        

            當(dāng)您需要定義8位字符或者16位字符時(shí),推薦您在Windows程序中使用的數(shù)據(jù)型態(tài)是CHAR和WCHAR。WCHAR定義后面的注釋是匈牙利標(biāo)記法的建議:一個(gè)基于WCHAR數(shù)據(jù)型態(tài)的變量可在前面附加上字母wc以說明一個(gè)寬字符。

            WINNT.H表頭文件進(jìn)而定義了可用做8位字符串指針的六種數(shù)據(jù)型態(tài)和四個(gè)可用做const 8位字符串指針的數(shù)據(jù)型態(tài)。這里精選了表頭文件中一些實(shí)用的說明數(shù)據(jù)型態(tài)語句:

            typedef CHAR * PCHAR, * LPCH, * PCH, * NPSTR, * LPSTR, * PSTR ;        
            typedef CONST CHAR * LPCCH, * PCCH, * LPCSTR, * PCSTR ;        

            前綴N和L表示「near」和「long」,指的是16位Windows中兩種大小不同的指標(biāo)。在Win32中near和long指標(biāo)沒有區(qū)別。

            類似地,WINNT.H定義了六種可作為16位字符串指針的數(shù)據(jù)型態(tài)和四種可作為const 16位字符串指針的數(shù)據(jù)型態(tài):

            typedef WCHAR * PWCHAR, * LPWCH, * PWCH, * NWPSTR, * LPWSTR, * PWSTR ;        
            typedef CONST WCHAR * LPCWCH, * PCWCH, * LPCWSTR, * PCWSTR ;        

            至此,我們有了數(shù)據(jù)型態(tài)CHAR(一個(gè)8位的char)和WCHAR(一個(gè)16位的wchar_t),以及指向CHAR和WCHAR的指標(biāo)。與TCHAR.H一樣,WINNT.H將TCHAR定義為一般的字符類型。如果定義了標(biāo)識(shí)符UNICODE(沒有底線),則TCHAR和指向TCHAR的指標(biāo)就分別定義為WCHAR和指向WCHAR的指標(biāo);如果沒有定義標(biāo)識(shí)符UNICODE,則TCHAR和指向TCHAR的指標(biāo)就分別定義為char和指向char的指標(biāo):

            #ifdef  UNICODE 
            typedef WCHAR TCHAR, * PTCHAR ;
            typedef LPWSTR LPTCH, PTCH, PTSTR, LPTSTR ; 
            typedef LPCWSTR LPCTSTR ;      
            #else
            typedef char TCHAR, * PTCHAR ;  
            typedef LPSTR LPTCH, PTCH, PTSTR, LPTSTR ; 
            typedef LPCSTR LPCTSTR ;   
            #endif
                    

            如果已經(jīng)在某個(gè)表頭文件或者其它表頭文件中定義了TCHAR數(shù)據(jù)型態(tài),那么WINNT.H和WCHAR.H表頭文件都能防止其重復(fù)定義。不過,無論何時(shí)在程序中使用其它表頭文件時(shí),都應(yīng)在所有其它表頭文件之前包含WINDOWS.H。

            WINNT.H表頭文件還定義了一個(gè)宏,該宏將L添加到字符串的第一個(gè)引號(hào)前。如果定義了UNICODE標(biāo)識(shí)符,則一個(gè)稱作 __TEXT的宏定義如下:

            #define __TEXT(quote) L##quote        

            如果沒有定義標(biāo)識(shí)符UNICODE,則像這樣定義__TEXT宏:

            #define __TEXT(quote) quote        

            此外, TEXT宏可這樣定義:

            #define TEXT(quote) __TEXT(quote)        

            這與TCHAR.H中定義_TEXT宏的方法一樣,只是不必操心底線。我將在本書中使用這個(gè)宏的TEXT版本。


            ???????
            ? 2.8.3.3 Windows頭文件也定義了ANSI/Unicode通用數(shù)據(jù)類型PTSTR和PCTSTR.這些數(shù)據(jù)類型既可以指ANSI字符串,也可以指Unicode字符串,這取決于當(dāng)編譯程序模塊時(shí)是否定義了UNICODE宏。這里的UNICODE宏沒有前置的下劃線。_UNICODE宏用于C運(yùn)行期頭文件。


            ?2.8.4 Windows字符串函數(shù)??

            ?
            2.8.4.1 Windows提供了一組對(duì)字符串進(jìn)行操作的通用函數(shù),這些函數(shù)是通過宏來實(shí)現(xiàn)的,這些宏既可以調(diào)用函數(shù)的Unicode版本,也可以調(diào)用函數(shù)的ANSI版本,這要根據(jù)編譯源代碼模塊時(shí)是否已經(jīng)定義了UNICODE而定。例如,如果沒有定義UNICODE,lstrcat函數(shù)將擴(kuò)展為lstrcatA。如果定義了UNICODE,lstrcat將擴(kuò)展為lstrcatW

            ???????? lstrcat??? 將一個(gè)字符串置于另一個(gè)字符串的結(jié)尾處
            ???????? lstrcmp??? 對(duì)兩個(gè)字符串進(jìn)行區(qū)分大小寫的比較??????? 對(duì)Windows函數(shù)CompareString的調(diào)用來實(shí)現(xiàn)的。

            ???????? lstrcmpi?? 對(duì)兩個(gè)字符串進(jìn)行不區(qū)分大小寫的比較????? 對(duì)Windows函數(shù)CompareString的調(diào)用來實(shí)現(xiàn)的。
            ???????? lstrcpy??? 將一個(gè)字符串拷貝到內(nèi)存中的另一個(gè)位置
            ???????? lstrlen??? 返回字符串的長度(按字符數(shù)來計(jì)量)

            ???????

            ?
            2.8.4.2 Windows還提供了<ShlWApi.h>頭文件包含一組范圍很廣的通用字符串操作函數(shù),類似于StrCat、StrChr、StrCmp和StrCpy等.這些字符串函數(shù)既有ANSI版本,也有Unicode版本,例如StrCatA和StrCatW,這取決于當(dāng)編譯程序模塊時(shí)是否定義了UNICODE宏,這些函數(shù)與C運(yùn)行期字符串函數(shù)(如strcpy和wcscpy很相似),但是該操作系統(tǒng)函數(shù)是操作系統(tǒng)的一個(gè)組成部分,操作系統(tǒng)的許多組件都使用這些函數(shù),而不使用C運(yùn)行期庫。建議最好使用操作系統(tǒng)函數(shù),而不要使用C運(yùn)行期字符串函數(shù)。這將有助于稍稍提高你的應(yīng)用程序的運(yùn)行性能,因?yàn)椴僮飨到y(tǒng)字符串函數(shù)常常被大型應(yīng)用程序比如操作系統(tǒng)的外殼進(jìn)程Explorer.exe所使用。由于這些函數(shù)使用得很多,因此,在你的應(yīng)用程序運(yùn)行時(shí),它們可能已經(jīng)被裝入RAM。



            ?2.9.4 在Unicode與ANSI之間轉(zhuǎn)換字符串

            ? 2.9.4.1
            <待續(xù)>



            ?2.9.5 成為符合ANSI和Unicode的應(yīng)用程序

            即使你不打算立即使用Unicode,最好也應(yīng)該著手將你的應(yīng)用程序轉(zhuǎn)換成符合Unicode 的應(yīng)用程序。下面是應(yīng)該遵循的一些基本原則:

            ? 將文本串視為字符數(shù)組,而不是chars 數(shù)組或字節(jié)數(shù)組。
            ? 將通用數(shù)據(jù)類型(如TCHAR和PTSTR)用于文本字符和字符串。
            ? 將顯式數(shù)據(jù)類型(如BYTE和PBYTE)用于字節(jié)、字節(jié)指針和數(shù)據(jù)緩存。
            ? 將TEXT宏用于原義字符和字符串。
            ? 執(zhí)行全局性替換(例如用PTSTR替換PSTR)。
            ? 修改字符串運(yùn)算問題。例如函數(shù)通常希望你在字符中傳遞一個(gè)緩存的大小,而不是字節(jié)。

            這意味著你不應(yīng)該傳遞sizeof(szBuffer),而應(yīng)該傳遞(sizeof(szBuffer)/sizeof(TCHAR)。另外,如果需要為字符串分配一個(gè)內(nèi)存塊,并且擁有該字符串中的字符數(shù)目,那么請(qǐng)記住要按字節(jié)來分配內(nèi)存。這就是說,應(yīng)該調(diào)用malloc(nCharacters *sizeof(TCHAR)),而不是調(diào)用malloc(nCharacters)。在上面所說的所有原則中,這是最難記住的一條原則,如果操作錯(cuò)誤,編譯器將不發(fā)出任何警告。



            ???? <Windows核心編程>
            ???? <Windows程序設(shè)計(jì)>



            2.9.5 C++ string

            我經(jīng)常在 C++ 程序中使用標(biāo)準(zhǔn)模板庫(STL)的 std::string 類,但在 使用 Unicode 時(shí)碰到了問題。在使用常規(guī) C 風(fēng)格的字符串時(shí),我可以使用 TCHAR 和 _T 宏,這樣針對(duì) Unicode 或 ASCII 均可以進(jìn)行編譯,但我 總是發(fā)現(xiàn)這種ASCII/Unicode的結(jié)合很難與 STL 的 string 類一起使用。你有什么好的建議嗎?
            是的,一旦知道 TCHAR 和_T 是如何工作的,那么這個(gè)問題很簡單。基本思想是 TCHAR 要么是char,要么是 wchar_t,這取決于 _UNICODE 的值:
              // abridged from tchar.h
            	#ifdef  _UNICODE
            	typedef wchar_t TCHAR;
            	#define __T(x) L ## x
            	#else
            	typedef char TCHAR;
            	#define __T(x) x
            	#endif
              當(dāng)你在工程設(shè)置中選擇 Unicode 字符集時(shí),編譯器會(huì)用 _UNICODE 定義進(jìn)行編譯。如果你選擇MBCS(多字節(jié)字符集),則編譯器將不會(huì)帶 _UNICODE 定義 。一切取決于_UNICODE 的值。同樣,每一個(gè)使用字符指針的 Windows API 函數(shù)會(huì)有一個(gè) A(ASCII) 和一個(gè) W(Wide/Unicode) 版本,這些版本的 實(shí)際定義也是根據(jù) _UNICODE 的值來決定:
            #ifdef UNICODE
            	#define CreateFile CreateFileW
            	#else
            	#define CreateFile CreateFileA
            	#endif
              同樣,_tprintf 和 _tscanf 對(duì)應(yīng)于 printf 和 scanf。所有帶"t"的版本使用 TCHARs 取代了chars。那么怎樣把以上的這些應(yīng)用到 std::string 上呢?很簡單。STL已經(jīng)有一個(gè)使用寬字符定義的wstring類 (在 xstring 頭文件中定義)。string 和 wstring 均是使用 typedef 定義的模板類,基于 basic_string, 用它可以創(chuàng)建任何字符類型的字符串類。以下就是 STL 定義的 string 和 wstring:
            // (from include/xstring)
            	  typedef basic_string< char, 
            	  char_traits< char >, allocator< char > >
            	  string;
            	  typedef basic_string< wchar_t, 
            	  char_traits< wchar_t >, allocator< wchar_t > > 
            	  wstring;
              模板被潛在的字符類型(char 或 wchar_t)參數(shù)化,因此,對(duì)于 TCHAR 版本,所要做的就是使用 TCHAR 來模仿定義。
               typedef basic_string< TCHAR, 
            	  char_traits< TCHAR >, 
            	  allocator< TCHAR > > 
            	  tstring;
              現(xiàn)在便有了一個(gè) tstring,它基于 TCHAR——也就是說,它要么是 char,要么是 wchar_t,這取決于 _UNICODE 的值。 以上示范并指出了 STL 是怎樣使用 basic_string 來實(shí)現(xiàn)基于任何類型的字符串的。定義一個(gè)新的 typedef 并不是解決此問題最有效的方法。一個(gè)更好的方法是基于 string 和wstring 來簡單 地定義 tstring,如下:
            #ifdef _UNICODE
            	#define tstring wstring
            	#else
            	#define tstring string
            	#endif
              這個(gè)方法之所以更好,是因?yàn)?STL 中已經(jīng)定義了 string 和 wstring,那為什么還要使用模板來定義一個(gè)新的和其中之一一樣的字符串類呢? 暫且叫它 tstring。可以用 #define 將 tstring 定義為 string 和 wstring,這樣可以避免創(chuàng)建另外一個(gè)模板類( 雖然當(dāng)今的編譯器非常智能,如果它把該副本類丟棄,我一點(diǎn)也不奇怪)。[編輯更新-2004/07/30:typedef 不創(chuàng)建新類,只是為某個(gè)類型引入限定范圍的名稱,typedef 決不會(huì)定義一個(gè)新的類型]。不管怎樣,一旦定義了 tstring,便可以像下面這樣編碼:
            tstring s = _T("Hello, world");
                  _tprintf(_T("s =%s\n"), s.c_str());
              basic_string::c_str 方法返回一個(gè)指向潛在字符類型的常量指針;在這里,該字符類型要么是const char*,要么是 const wchar_t*。
              Figure 2 是一個(gè)簡單的示范程序,舉例說明了 tstring 的用法。它將“Hello,world”寫入一個(gè)文件,并報(bào)告寫了多少個(gè)字節(jié)。我對(duì) 工程進(jìn)行了設(shè)置,以便用 Unicode 生成 debug 版本,用 MBCS 生成 Release 版本。你可以分別進(jìn)行編譯/生成并運(yùn)行程序,然后比較結(jié)果。Figure 3 顯示了例子的運(yùn)行情況。


            Figure 3 運(yùn)行中的 tstring

              順便說一下,MFC 和 ATL 現(xiàn)在已經(jīng)聯(lián)姻,以便都使用相同的字符串實(shí)現(xiàn)。結(jié)合后的實(shí)現(xiàn)使用一個(gè)叫做 CStringT 的模板類,這在某種意義上 ,其機(jī)制類似 STL 的 basic_string,用它可以根據(jù)任何潛在的字符類型來創(chuàng)建 CString 類。在 MFC 包含文件 afxstr.h 中定義了三種字符 串類型,如下:
            typedef ATL::CStringT< wchar_t, 
            	  StrTraitMFC< wchar_t > > CStringW;
            	  typedef ATL::CStringT< char, 
            	  StrTraitMFC< char > > CStringA;
            	  typedef ATL::CStringT< TCHAR, 
            	  StrTraitMFC< TCHAR > > CString;
            CStringW,CStringA 和 CString 正是你所期望的:CString 的寬字符,ASCII 和 TCHAR 版本。
              那么,哪一個(gè)更好,STL 還是 CStirng?兩者都很好,你可以選擇你最喜歡的一個(gè)。但有一個(gè)問題要考慮到:就是你想要鏈接哪個(gè)庫,以及你是否已經(jīng)在使用 MFC/ATL。從編碼 的角度來看,我更喜歡 CString 的兩個(gè)特性:
              其一是無論使用寬字符還是char,都可以很方便地對(duì) CString 進(jìn)行初始化。
            CString s1 = "foo";
            	CString s2 = _T("bar");	
              這兩個(gè)初始化都正常工作,因?yàn)?CString 自己進(jìn)行了所有必要的轉(zhuǎn)換。使用 STL 字符串,你必須使用_T()對(duì) tstring 進(jìn)行初始化,因?yàn)槟? 無法通過一個(gè)char*初始化一個(gè)wstring,反之亦然。
              其二是 CString 對(duì) LPCTSTR 的自動(dòng)轉(zhuǎn)換操作,你可以像下面這樣編碼:
              CString s;
            	LPCTSTR lpsz = s;
              另一方面,使用 STL 必須顯式調(diào)用 c_str 來完成這種轉(zhuǎn)換。這確實(shí)有點(diǎn)挑剔,某些人會(huì)爭辯說,這樣能更好地了解何時(shí)進(jìn)行轉(zhuǎn)換。比如, 在C風(fēng)格可變參數(shù)的函數(shù)中使用 CString 可能會(huì)有麻煩,像 printf:
              printf("s=%s\n", s); // 錯(cuò)誤
            	printf("s=%s\n", (LPCTSTR)s); // 必需的	
              沒有強(qiáng)制類型轉(zhuǎn)換的話,得到的是一些垃圾結(jié)果,因?yàn)?printf 希望 s 是 char*。我敢肯定很多讀者都犯過這種錯(cuò)誤。防止這種災(zāi)禍?zhǔn)?STL 設(shè)計(jì)者不提供轉(zhuǎn)換操作符的一個(gè)毋庸置疑的理由。而是堅(jiān)持要你調(diào)用 c_str。一般來講,喜歡使用 STL 家伙趨向于理論和學(xué)究氣,而 Redmontonians(譯者:指微軟)的大佬們則更注重實(shí)用和散漫。嘿,不管怎樣,std::string 和 CString 之間的實(shí)用差別是微不足道的。



            作者簡介
              Paul DiLascia 是一名自由作家,顧問和 Web/UI 設(shè)計(jì)者。他是《Writing Reusable Windows Code in C++》書(Addison-Wesley, 1992)的作者。通過 http://www.dilascia.com 可以獲得更多了解。  
            本文出自 MSDN Magazine August 2004 期刊,可通過當(dāng)?shù)貓?bào)攤獲得,或者最好是 訂閱

            本文由 VCKBASE MTT 翻譯
            ,http://www.vckbase.com/document/viewdoc/?id=1293







            posted on 2011-08-13 01:32 Vcer-JZ 閱讀(905) 評(píng)論(0)  編輯 收藏 引用 所屬分類: MFC

            導(dǎo)航

            統(tǒng)計(jì)

            隨筆分類

            隨筆檔案

            搜索

            最新評(píng)論

            亚洲国产精品无码成人片久久| 亚洲综合精品香蕉久久网97 | 精品久久久久成人码免费动漫| 久久亚洲视频| 国产69精品久久久久9999APGF| 无码人妻久久久一区二区三区| 欧美日韩中文字幕久久伊人| 亚洲精品无码专区久久久| 精品久久久久中文字幕日本| 亚洲日本va午夜中文字幕久久| 青青草原精品99久久精品66| 婷婷综合久久中文字幕| 久久久无码精品亚洲日韩蜜臀浪潮| 国产V综合V亚洲欧美久久| 欧美久久一级内射wwwwww.| 精品蜜臀久久久久99网站| 色欲综合久久躁天天躁| 欧美精品一本久久男人的天堂| 中文字幕无码精品亚洲资源网久久| 精品久久久久久国产三级 | 思思久久99热免费精品6| 99国产精品久久久久久久成人热| 久久午夜免费视频| 国产精品伦理久久久久久| 久久精品亚洲精品国产色婷| 久久久久波多野结衣高潮| 久久男人中文字幕资源站| 久久99精品国产麻豆婷婷| 91视频国产91久久久| 久久久久亚洲av无码专区喷水| 亚洲日韩中文无码久久| 久久香蕉国产线看观看精品yw| 久久人妻无码中文字幕| 亚洲第一极品精品无码久久| 久久婷婷五月综合成人D啪| 欧美亚洲国产精品久久高清 | 久久精品9988| 色综合久久中文色婷婷| 国产精品久久久久乳精品爆| 久久97久久97精品免视看| 久久人搡人人玩人妻精品首页|