Windows核心編程:字符和字符串處理

作者:shenzi

鏈接:http://hi.csdn.net/shenzi

Windows核心編程:字符和字符串處理

1.字符編碼

    ANSI 字符,一個字符一字節(8位),最多隻能表達256個字符。
    UTF 的全稱是Unicode Transformation Format(Unicode轉換格式)。
    UTF-16 將 每個字符編碼爲兩個字符(16位)Windows使用的Unicode使用UTF-16編碼,因爲全球各地使用的大部分語言很容易用一個16位值來表示。 但是對於某些語言16位還難以表示所有字符,對於這些語言,UTF-16支持使用代理(surrogate),用32位(四字節)來表示一個字符。 UTF-16在節省空間和簡化編碼者兩個目標之間,提供了很好的折衷。
    .NET Framework始終使用UTF-16來編碼所有字符和字符串,所以在開發Windows應用程序中,如果需要在本機代碼(native code)和託管代碼(managed code)之間傳遞字符或字符串,使用UTF-16能改進性能和減少內存消耗。
    UTF-8 將一些字符編碼爲1個字節,一些字符編碼爲2個字節,一些字符編碼爲3個字節,一些字符編碼爲4個字節。
   UTF-32 將每個字符編碼爲4個字節。
2.字符串數據類型
    char:            表示一個8位ANSI字符;
     wchar_t:     表示一個16位Unicode(UTF-16)字符;
                      (Microsoft C/C++編譯器內建的數據類型,編譯器只有指定了/Zc:wchar_t,纔會定義這個數據類型。Visual Studio                            新建一個C++項目這個編譯器開關時制定的。這樣才能藉助於編譯器天生就能理解的內建基元類型來更好的操作                                Unicode字符。)

    typedef unsigned short wchar_t;    //wchar_t定義爲無符號短整型;
  
// A 16-bit character
    wchar_t c = L'A';

   // An array up to 99 16-bit characters and a 16-bit terminating zero.
    wchar_t szBuffer[100] = L"A String";
   字符串之前加大寫“L”是告訴編譯器該字符串應當編譯爲一個Unicode字符串。

  
Windows開發團隊定義了自己的數據類型。
   //WinNT.h
  
typedef char CHAR; // An 8-bit character
   typedef wchar_t WCHAR; // A 16-bit character


     //Pointer to 8-bit character(s)
     typedef CHAR *PCHAR;
     typedef CHAR *PSTR;
     typedef CONST CHAR *PCSTR


     //Pointer to 16-bit character(s)
     typedef WCHAR *PWCHAR;
     typedef WCHAR *PWSTR;
     typedef CONST WCHAR *PCWSTR;


     #ifdef UNICODE

   typedef WCHAR TCHAR, *PTCHAR, PTSTR;
   typedef CONST WCHAR *PCTSTR;
   #define __TEXT(quote) quote // r_winnt

   #define __TEXT(quote) L##quote

   #else

   typedef CHAR TCHAR, *PTCHAR, PTSTR;
   typedef CONST CHAR *PCTSTR;
   #define __TEXT(quote) quote

   #endif

   #define TEXT(quote) __TEXT(quote)

    利用以上類型和宏來寫代碼,無論使用ANSI還是Unicode字符,它都能通過編譯。如下:
    
 //如果UNICODE被定義, 則爲16位字符; 否則爲8位字符
   TCHAR c = TEXT('A');

   //
如果UNICODE被定義, 則爲16位字符; 否則爲8位字符
   TCHAR szBuffer[100] = TEXT("A String");
3.Windows中的Unicode 函數 和ANSI 函數
    自Windows NT起,Windows的所有版本都完全用Unicode構建也 就是說,所有核心函數(創建窗口,顯示文本,進行字符串處理等等)都需要Unicode字符串。調用Windows函數時,如果向它傳入一個ANSI字符 串,那麼函數首先會把字符串轉換爲Unicode,再把結果傳給操作系統。如果希望函數返回ANSI字符串,那麼操作系統會先把Unicode字符串轉換 爲ANSI字符串,再把結果返回給我們的應用程序。爲了執行這些字符串轉換,系統會產生時間和內存上的開銷。
    
#ifdef UNICODE
    #define CreateWindowEx CreateWindowExW
  #else
    #define CreateWindowEx CreateWindowExA
  #endif

    Visual Studio創建一個新項目時默認會定義UNICODE,所以調用
CreateWindowExW ,即Unicode版函數。ANSI版函數 CreateWindowExA ,只是一個轉換層,它負責分配內存,以便將ANSI字符串轉換爲Unicode字符串,然後再調用 Unicode版函數 CreateWindowExW。所以爲了減少時間和內存上的 耗費,使用Unicode來開發程序。
    所有需要字符串作爲參數的COM藉口方法都只接受Unicode字符串。
4.C運行庫中的Unicode和ANSI
    爲了使源代碼既能用ANSI編譯,又能用Unicode編譯TChar.h定義了一下宏:
     #ifdef _UNICODE
         #define _tcslen wcslen
     #else
        #define _tcslen strlen
     #endif

    在應用程序中應確保同時定義了UNICODE和_UNICODE
5.爲何要用Unicode
  • Unicode有利於應用程序的本地化;  
  • 使用 Unicode,只需發佈一個二進制(.exe或.dll)文件,即可支持所有語言;
  • Unicode提升應用程序的效率,代碼執行更快,佔用內存更少。Windows內部的一切工作都是使用 Unicode字符和 Unicode字符串來進行的。假如我們堅持使用ANSI字符或字符串,Windows將被迫分配內存,將字符或字符串轉換爲Unicode形式;
  • 使用 Unicode,應用程序能夠輕鬆的調用尚未棄用的Windows函數,因爲一些Windows函數提供的版本只能處理 Unicode字符和字符串;
  • 使用 Unicode,應用程序的代碼很容易與COM集成(要求使用 Unicode );
  • 使用 Unicode,應用程序的代碼很容易與.NET Framework集成(要求使用 Unicode );
  • 使用 Unicode,能保證應用程序的代碼能夠輕鬆操縱我們自己的資源(其中的字符串總是 Unicode形式 )。
6.推薦的字符和字符串處理方式
  • 開始將文本字符串想象爲字符的數組,而不是 char 或字節的數組;
  • 用通用數據類型(如 TCHAR/PTSTR )來表示文本字符和字符串;
  • 用明確的數據類型(如 BYTE PBYTE )來表示字節,字節指針和數據緩衝區;
  • TEXT _T 宏來表示字面量字符和字符串,但爲了保持一致性和更好的可讀性,請避免兩者混用;
  • 執行全局替換(例如用 PTSTR 替換 PSTR ;
  • 修改與字符串有關的計算。例如,函數經常希望我們傳給它緩衝區打小的字符數,而不是字節數。這意味着我們應該傳入 _countoof(szBuffer), 而不是 sizeof(szBuffer) 。而且,如果需要爲一個字符串分配一個內存塊,而且知道字符串中的字符數,那麼要 記住內存是以字節來分配的
  • 避免使用 printf 系列函數,正確的做法是使用 MultiByteToWideChar WideCharToMultiByte 函數。
  • Unicode和_ Unicode符號要麼同時指定,要麼都不指定。

對於字符串處理函數,應該遵循以下基本準則:

  • 始終使用安全的字符串處理函數,比如後綴爲 _s 的函數,或者前綴爲 StringCch 的函數。後者主要在我們想明確控制截斷的時候使用瞭如果不像明確控制截斷,首選前者。
  • 利用 /GS /RTCs 編譯器標誌來自動檢測緩衝區溢出。
  • 不要使用 Kernel32 方法來進行字符串處理,比如 lstrcat lstrcpy
  • 在應用程序的代碼中,需要比較兩種字符串,應使用 CompareStringOrdinal 來進行比較。
7.Unicode與ANSI字符串轉換       int MultiByteToWideChar(
    UINT
uCodePage , // code page
    DWORD dwFlags , // character-type options
    PCSTR pMultiByteStr , // string to map
    int cbMultiByte , // number of bytes in string
    PWSTR pWideCharStr , // wide-character buffer
    int cchWideChar // size of buffer
    );
  • 調用 MultiByteToWideChar, pWideCharStr 傳入 NULL,爲cchWideChar參數傳入0,爲cbMultiByte參數傳入-1;
  • 分配一塊足以容納轉換後的Unicode字符串的內存。它的大小是一個 MultiByteToWideChar 調用的返回值乘以sizeof(wchar_t);  
  • 再次調用 MultiByteToWideChar ,這一次將緩衝區地址作爲pWideCharStr參數的值傳入,將第一次 MultiByteToWideChar 調用的返回值乘以sizeof(wchar_t)後得到的大小作爲cchWideChar參數的值傳入;
  • 使用轉換後的字符串;
  • 釋放Unicode字符串佔用的內存塊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章