作者:shenzi
鏈接:http://hi.csdn.net/shenzi
Windows核心編程:字符和字符串處理
1.字符編碼
UTF 的全稱是Unicode Transformation Format(Unicode轉換格式)。
.NET Framework始終使用UTF-16來編碼所有字符和字符串,所以在開發Windows應用程序中,如果需要在本機代碼(native code)和託管代碼(managed code)之間傳遞字符或字符串,使用UTF-16能改進性能和減少內存消耗。
UTF-8 將一些字符編碼爲1個字節,一些字符編碼爲2個字節,一些字符編碼爲3個字節,一些字符編碼爲4個字節。
UTF-32 將每個字符編碼爲4個字節。
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");
#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif
Visual Studio創建一個新項目時默認會定義UNICODE,所以調用 CreateWindowExW ,即Unicode版函數。ANSI版函數 CreateWindowExA ,只是一個轉換層,它負責分配內存,以便將ANSI字符串轉換爲Unicode字符串,然後再調用 Unicode版函數 CreateWindowExW。所以爲了減少時間和內存上的 耗費,使用Unicode來開發程序。
所有需要字符串作爲參數的COM藉口方法都只接受Unicode字符串。
#ifdef _UNICODE
#define _tcslen wcslen
#else
#define _tcslen strlen
#endif
在應用程序中應確保同時定義了UNICODE和_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形式 )。
- 開始將文本字符串想象爲字符的數組,而不是 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 來進行比較。
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字符串佔用的內存塊。