一、
Unicode標準:
每個Unicode字符都是使用UTF-16編碼,UTF-16將每個字符編碼爲2個字節,UTF-16在節省空間和簡化編碼之間提供了一個良好的折衷。
ANSI標準:
使用UTF-8編碼,一個字符使用一個字節,佔8位。c語言的char類型用來表示一個8位的ANSI字符。
二、
WIndows系統與Unicode標準:
自Windows NT起,Windows所有版本都採用Unicode標準,所有核心函數都採用Unicode字符串,如果調用一個函數傳入的參數是ANSI字符串,那麼函數會先將其轉換衝Unicode字符串,再傳給操作系統,如果希望函數返回ANSI字符串,那麼操作系統會先將Unicode字符串轉換成ANSI字符串,這些轉換都在幕後進行的,因此係統會產生時間和內存上的消耗。
三、
Microsoft的C/C++編譯器與Unicode字符:
現在Microsoft的C/C++編譯器定義了一個內建的數據類型wchar_t,它表示一個16位的Unicode(UTF-16)字符,在默認情況下,VS建立一個新項目時,是使用Unicode標準字符的。
聲明Unicode字符或字符串的方法:wchar_t c = L'A'; 在前面加個L表示通知編譯器該字符(串)應當編譯爲Unicode字符。輸出要用std::wcout。
四、
源代碼如何保持一致性:
windows開發團隊與c語言稍有區別,他們在Windows頭文件WinNT.h中定義了以下數據類型:
typedef char CHAR ;
typedef wchar_t WCHAR;
//指針
typedef CHAR *PCHAR;
typedef CHAR *PSTR;
typedef CONST CHAR *PCSTR;
typedef WCHAR PWCHAR;
typedef WCHAR PWSTR;
typedef CONST WCHAR *PCWSTR;
在源代碼中,具體使用哪種字符類型不重要,重要的是保持一致性,增加代碼的可維護性, WinNT.h中定義了以下類型和宏:
#ifdef UNICODE
typedef WCHAR TCHAR ,*PTCHAR, PTSTR;
typedef CONST WCHAR *PCTSTR;
#else
typedef WCHAR TCHAR ,*PTCHAR, PTSTR;
typedef CONST WCHAR *PCTSTR;
所以無論採用哪種字符標準,使用TCHAR都是編譯通過 TCHAR szBuffer[100] = _T("hello world!"); 故TCHAR稱爲通用類型。
此外對一些API函數也做了一些保持一致性的修改,如下:
#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif
五、
C運行庫中的Unicode函數和ANSI函數:
對於計算字符串長度的函數,C運行庫中,strlen是返回ANSI字符串的長度,與之對於的是wcslen,返回的是Unicode字符串的長度。
在TChar.h文件中,定義了以下宏:
#ifdef UNICODE
#define _tcslen wcslen
#else
#define _tcslen strlen
#endif
所以在代碼中不用管是否採用Unicode標準,可以直接調用_tcslen函數。
但是,任何修改字符串的函數都存在一個安全隱患,如果目標字符串的緩衝區不夠大,無法容下所生成的字符串,將會導致內存中的數據被破壞,例如strcpy和wcscpy,所以最好是用wcscat這樣指定緩衝區長度的字符串處理函數。相反的,像stlen和wcslen等不會修改傳入字符串的函數則是安全的。
目前微軟提供了一些新版本的字符串安全處理函數(tchar.h文件裏),即在函數名後面加_s ,例如_tcscpy_s,_tcscat_s,memcpy_s,memmove_s。它們的首要任務就是驗證傳給它們的參數值。例如指針不爲NULL,整數在有範圍內,緩衝區是否能容納結果大小等。
這裏我介紹一個宏_countof, 一些函數通常需要我傳入某個參數的緩衝區的字符數,而非字節數,所以我們就應該傳入_countof(szBuffer)而不是sizeof(szBuffer) 。在手動分配一塊內存的時候,要記住內存是以字節累分配的,這意味着我們必須調用malloc(nChars * sizeof(TCHAR))。
VC中有一個計算數組元素個數的MACRO
代碼如下:
#if !defined(_countof)
#if !defined(__cplusplus)
#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#else
extern "C++"
{
template <typename _CountofType, size_t _SizeOfArray>
char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
#define _countof(_Array) sizeof(*__countof_helper(_Array))
}
#endif
#endif
C++版本的實現充分地利用了函數模板的參數自動推導機制,但我始終沒聊到函數指針也可以模板化,
六、寬字符與窄字符轉換
size_t mbstowcs(wchar_t *wcstr, const char *mbstr, size_t count)//由一個窄字符轉換到一個寬字符
size_t wcstombs(char *mbstr, const wchar_t *wcstr, size_t count)//由一個寬字符轉換到一個窄字符