• <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)行期庫對Unicode的支持

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

            ?????????
            typedef unsigned short wchar_t;
            ????????
            ? 2.8.1.2 添加了與ANSI C字符串對應(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個通用宏。

            ???????? #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字符和字符串。但有個壞消息:在Windows程序中不能使用printf。雖然Windows程序中可以使用大多數(shù)C的執(zhí)行時期鏈接庫-實(shí)際上,許多程序?qū)懽髡吒敢馐褂肅內(nèi)存管理和文件I/O函數(shù)而不是Windows中等效的函數(shù)-Windows對標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出沒有概念。在Windows程序中可使用fprintf,而不是printf。還有一個好消息,那就是仍然可以使用sprintf及sprintf系列中的其它函數(shù)來顯示文字。這些函數(shù)除了將內(nèi)容格式化輸出到函數(shù)第一個參數(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 一個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位字符時,推薦您在Windows程序中使用的數(shù)據(jù)型態(tài)是CHAR和WCHAR。WCHAR定義后面的注釋是匈牙利標(biāo)記法的建議:一個基于WCHAR數(shù)據(jù)型態(tài)的變量可在前面附加上字母wc以說明一個寬字符。

            WINNT.H表頭文件進(jìn)而定義了可用做8位字符串指針的六種數(shù)據(jù)型態(tài)和四個可用做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(一個8位的char)和WCHAR(一個16位的wchar_t),以及指向CHAR和WCHAR的指標(biāo)。與TCHAR.H一樣,WINNT.H將TCHAR定義為一般的字符類型。如果定義了標(biāo)識符UNICODE(沒有底線),則TCHAR和指向TCHAR的指標(biāo)就分別定義為WCHAR和指向WCHAR的指標(biāo);如果沒有定義標(biāo)識符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)在某個表頭文件或者其它表頭文件中定義了TCHAR數(shù)據(jù)型態(tài),那么WINNT.H和WCHAR.H表頭文件都能防止其重復(fù)定義。不過,無論何時在程序中使用其它表頭文件時,都應(yīng)在所有其它表頭文件之前包含WINDOWS.H。

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

            #define __TEXT(quote) L##quote        

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

            #define __TEXT(quote) quote        

            此外, TEXT宏可這樣定義:

            #define TEXT(quote) __TEXT(quote)        

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


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


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

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

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

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

            ???????

            ?
            2.8.4.2 Windows還提供了<ShlWApi.h>頭文件包含一組范圍很廣的通用字符串操作函數(shù),類似于StrCat、StrChr、StrCmp和StrCpy等.這些字符串函數(shù)既有ANSI版本,也有Unicode版本,例如StrCatA和StrCatW,這取決于當(dāng)編譯程序模塊時是否定義了UNICODE宏,這些函數(shù)與C運(yùn)行期字符串函數(shù)(如strcpy和wcscpy很相似),但是該操作系統(tǒng)函數(shù)是操作系統(tǒng)的一個組成部分,操作系統(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)行時,它們可能已經(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ù)通常希望你在字符中傳遞一個緩存的大小,而不是字節(jié)。

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



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



            2.9.5 C++ string

            我經(jīng)常在 C++ 程序中使用標(biāo)準(zhǔn)模板庫(STL)的 std::string 類,但在 使用 Unicode 時碰到了問題。在使用常規(guī) C 風(fēng)格的字符串時,我可以使用 TCHAR 和 _T 宏,這樣針對 Unicode 或 ASCII 均可以進(jìn)行編譯,但我 總是發(fā)現(xiàn)這種ASCII/Unicode的結(jié)合很難與 STL 的 string 類一起使用。你有什么好的建議嗎?
            是的,一旦知道 TCHAR 和_T 是如何工作的,那么這個問題很簡單。基本思想是 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 字符集時,編譯器會用 _UNICODE 定義進(jìn)行編譯。如果你選擇MBCS(多字節(jié)字符集),則編譯器將不會帶 _UNICODE 定義 。一切取決于_UNICODE 的值。同樣,每一個使用字符指針的 Windows API 函數(shù)會有一個 A(ASCII) 和一個 W(Wide/Unicode) 版本,這些版本的 實(shí)際定義也是根據(jù) _UNICODE 的值來決定:
            #ifdef UNICODE
            	#define CreateFile CreateFileW
            	#else
            	#define CreateFile CreateFileA
            	#endif
              同樣,_tprintf 和 _tscanf 對應(yīng)于 printf 和 scanf。所有帶"t"的版本使用 TCHARs 取代了chars。那么怎樣把以上的這些應(yīng)用到 std::string 上呢?很簡單。STL已經(jīng)有一個使用寬字符定義的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ù)化,因此,對于 TCHAR 版本,所要做的就是使用 TCHAR 來模仿定義。
               typedef basic_string< TCHAR, 
            	  char_traits< TCHAR >, 
            	  allocator< TCHAR > > 
            	  tstring;
              現(xiàn)在便有了一個 tstring,它基于 TCHAR——也就是說,它要么是 char,要么是 wchar_t,這取決于 _UNICODE 的值。 以上示范并指出了 STL 是怎樣使用 basic_string 來實(shí)現(xiàn)基于任何類型的字符串的。定義一個新的 typedef 并不是解決此問題最有效的方法。一個更好的方法是基于 string 和wstring 來簡單 地定義 tstring,如下:
            #ifdef _UNICODE
            	#define tstring wstring
            	#else
            	#define tstring string
            	#endif
              這個方法之所以更好,是因?yàn)?STL 中已經(jīng)定義了 string 和 wstring,那為什么還要使用模板來定義一個新的和其中之一一樣的字符串類呢? 暫且叫它 tstring。可以用 #define 將 tstring 定義為 string 和 wstring,這樣可以避免創(chuàng)建另外一個模板類( 雖然當(dāng)今的編譯器非常智能,如果它把該副本類丟棄,我一點(diǎn)也不奇怪)。[編輯更新-2004/07/30:typedef 不創(chuàng)建新類,只是為某個類型引入限定范圍的名稱,typedef 決不會定義一個新的類型]。不管怎樣,一旦定義了 tstring,便可以像下面這樣編碼:
            tstring s = _T("Hello, world");
                  _tprintf(_T("s =%s\n"), s.c_str());
              basic_string::c_str 方法返回一個指向潛在字符類型的常量指針;在這里,該字符類型要么是const char*,要么是 const wchar_t*。
              Figure 2 是一個簡單的示范程序,舉例說明了 tstring 的用法。它將“Hello,world”寫入一個文件,并報(bào)告寫了多少個字節(jié)。我對 工程進(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)使用一個叫做 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 版本。
              那么,哪一個更好,STL 還是 CStirng?兩者都很好,你可以選擇你最喜歡的一個。但有一個問題要考慮到:就是你想要鏈接哪個庫,以及你是否已經(jīng)在使用 MFC/ATL。從編碼 的角度來看,我更喜歡 CString 的兩個特性:
              其一是無論使用寬字符還是char,都可以很方便地對 CString 進(jìn)行初始化。
            CString s1 = "foo";
            	CString s2 = _T("bar");	
              這兩個初始化都正常工作,因?yàn)?CString 自己進(jìn)行了所有必要的轉(zhuǎn)換。使用 STL 字符串,你必須使用_T()對 tstring 進(jìn)行初始化,因?yàn)槟? 無法通過一個char*初始化一個wstring,反之亦然。
              其二是 CString 對 LPCTSTR 的自動轉(zhuǎn)換操作,你可以像下面這樣編碼:
              CString s;
            	LPCTSTR lpsz = s;
              另一方面,使用 STL 必須顯式調(diào)用 c_str 來完成這種轉(zhuǎn)換。這確實(shí)有點(diǎn)挑剔,某些人會爭辯說,這樣能更好地了解何時進(jìn)行轉(zhuǎn)換。比如, 在C風(fēng)格可變參數(shù)的函數(shù)中使用 CString 可能會有麻煩,像 printf:
              printf("s=%s\n", s); // 錯誤
            	printf("s=%s\n", (LPCTSTR)s); // 必需的	
              沒有強(qiáng)制類型轉(zhuǎn)換的話,得到的是一些垃圾結(jié)果,因?yàn)?printf 希望 s 是 char*。我敢肯定很多讀者都犯過這種錯誤。防止這種災(zāi)禍?zhǔn)?STL 設(shè)計(jì)者不提供轉(zhuǎn)換操作符的一個毋庸置疑的理由。而是堅(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 閱讀(899) 評論(0)  編輯 收藏 引用 所屬分類: MFC

            導(dǎo)航

            統(tǒng)計(jì)

            隨筆分類

            隨筆檔案

            搜索

            最新評論

            久久精品无码专区免费| 国产激情久久久久影院小草| 国产一区二区久久久| 99久久精品免费看国产一区二区三区| 婷婷久久香蕉五月综合加勒比 | 99re久久精品国产首页2020| 久久精品成人免费网站| 久久国产亚洲精品| 久久婷婷综合中文字幕| 久久综合日本熟妇| 欧美精品一区二区精品久久 | 久久久久久久久久久久久久| 久久人人爽人人爽人人AV东京热| 精品99久久aaa一级毛片| 精品久久久久久久无码| 久久伊人精品一区二区三区| 国产精久久一区二区三区| 性欧美丰满熟妇XXXX性久久久 | 久久精品麻豆日日躁夜夜躁| 久久高清一级毛片| 青青青国产成人久久111网站| 久久精品国产亚洲av麻豆图片 | 亚洲va久久久噜噜噜久久| 国内精品久久久久影院网站| 久久亚洲精精品中文字幕| 久久久久国产精品人妻| 久久伊人色| 老司机午夜网站国内精品久久久久久久久| 999久久久免费精品国产| 久久婷婷五月综合97色一本一本| 国产精品乱码久久久久久软件| 精品久久久久久无码人妻热 | 久久精品国产精品亚洲精品| 日本精品久久久久影院日本| 久久久WWW成人| 久久夜色撩人精品国产| 久久夜色精品国产| 亚洲欧美国产日韩综合久久| 亚洲精品99久久久久中文字幕| 亚洲欧美国产日韩综合久久| 狠狠色丁香久久婷婷综合图片|