VC中的Unicode
學習C語言的時候您應該接觸過ASCII碼。學習本章的內容需要ASCII知識。
學習Unicode有必要了解字符集的歷史。從最早的象形字開始,我們使用字符文字已經有近6000年了。19世紀的幾個發明家發明了電報,當時在電報中使用的代碼是Morse代碼。字母表中的每個字符對應于一系列短和長的脈沖。
計算機是處理的數據其實是一系列1和0。每一段數字都代表一種字符。這就是ASCII碼。7位數的ASCII碼對于美國的字符集支持得很好。不幸的是地球上有一百多個國家和地區,2000多個民族。對于美國以外的用戶來講在計算機中顯示自己國家的文字困難重重。
尤其是中國,日本,朝鮮更是如此。以中國為例,有數也數不清的漢字。辦法總是有的。人們引入了"代碼頁"和"雙字節字符集"的概念。這種編碼方式非常龐大和復雜,不利于維護。這個時候Unicode應運而生了。
Unicode的解決方案非常簡單。既然不能用7位或者8位數值表示,那么我們應該試一下更寬的值。例如16位,這樣就允許表示65536個字符。Unicode和ASCII是兼容的。也就是說,前128個字符的數值是相同的。
Unicode的最大好處是只有一個字符集。當然Unicode也有缺點,Unicode占用的內存是ASCII碼的兩倍。而且人們還不太習慣Unicode。
對于程序員來講,8位的ASCII碼和16位的Unicode是我們必須面對的問題。為了解決寬字符(16位)問題,Windows在頭文件中定義了"新"數據類型。
typedef?unsigned short?wchar_t;
可以看出wchar_t其實是16位的無符號短整型數。Windows用這種方法存貯16位字符。
wchar_t *p =?L"Hello!";
在"Hello!"前有一個大寫字母L(代表long)。這將告訴編譯器該字符串按寬字符保存。即每個字符占用2個字符。存貯該字符串需要14個字節。字符串末尾還有一個/0也需要2個字節。
我們都知道如何獲得字符串的長度。
int?iLength;
char?*pc = "Hello!";
iLength = strlen(pc);
函數strlen()返回字符串的長度,長度將不包括末尾的/0。變量iLength將等于6,也就是字符串中的字符數。
接下來我們試著用strlen()檢查寬字符的字符串。
wchar_t *pw = L"Hello!";
iLength = strlen(pw);
strlen()的參數應該是char類型的指針,但是現在卻接受了一個unsigned short類型的指針。編譯后您會發現iLength等于1。
why?字符串"Hello!"中的6個字符寬字符代碼如下:
0x0048 0x0065 0x006c 0x006c 0x006f 0x0021
Intel處理器在內存中將其存為:
48 00 65 00 6c 00 6c 00 6f 00 21 00
strlen()的工作過程是遇到0就結束。因為0表示一個字符串的結束。當讀完"48"后strlen()遇到的是0,所以strlen()返回1。
由上例可以看出C語言的函數無法正確處理寬字符。在參數中有字符串的函數全部需要重寫。strlen()的寬字符版本是wcslen(),并且在STRING.H中和WCHAR.H中均有聲明.
現在我們知道,要得到寬字符串的長度,可以調用
iLength = wcslen(pw);
該函數返回將返回字符串中的字符數6。請記住,改成寬字節后字符串的字符長度不變,只是字節長度改變了。千萬不要混淆。
因為Unicode占用兩倍的存儲空間,所以寬字節運行庫中的函數比常規的函數大。所以最好是建立兩個版本的程序,一個處理ASCII字符串,另一個處理Unicode字符串。但是這樣以來又引來了另一個小問題。因為每一個實現特定功能的函數都有兩個版本,所以名字不好記。不管是ASCII版本還是Unicode版本,都用相同的名字該多好啊?幸好這個問題已經得到了解決。
解決辦法是使用Visual C++包含的TCHAR.H頭文件。該頭文件不是標準C的一部分。為了與標準C的頭文件分別開來,該頭文件內定義的每個函數和宏定義的前面都有一條下劃線。
TCHAR.H為需要字符串的標準運行庫函數提供了一系列的替代名稱。有時這些名稱被稱為"通用"函數名,因為它們既可以指向函數的Unicode版本,也可以指向ASCII版本。
以_tcslen()為例如果定義了_UNICODE的標識符,并且程序中包含了TCHAR.H,那么_tcslen()就定義為wcslen():
#define _tcslen wcslen
如果沒有定義_UNICODE,則_tcslen()被定義為strlen()。
#define _tcslen strlen
TCHAR.H還用一個新的數據類型TCHAR來解決兩種字符數據類型的問題。如果定義了_UNICODE標識符,那么TCHAR就是wchar_t:
typedef wchar_t TCHAR;
否則TCHAR就是char:
typedef char TCHAR;
還記得第一章里出現過的TEXT()嗎?那是為了兼容UNICODE字符集所做的改動。下面就來看看TEXT()在頭文件中是怎么定義的。
#define __T(x)??? L##x
后面的L##x您可能看不懂。很少有書提到它。但那確實是標準C預處理的一部分。這一對"##"稱為粘貼號(token paste)。看來我們對標準C的了解還不夠。是時候買本"The C Programming Language"了。它將字母L添加到宏參數上。
__T("Hello!") 等于 L##"Hello!" 等于 L"Hello!"。
此外還有兩個宏與__T定義相同:
#define _T(x) __T(x)
#define _TEXT(x) __T(x)
WINNT.H頭文件中還定義了一個宏,該宏也跟__T一樣,將L添加到字符串前。
#ifdef UNICODE
#define __TEXT(quote) L##quote
#else
#define __TEXT(quote) quote
#endif
#define TEXT(quote) __TEXT(quote)
轉載:http://www.cnblogs.com/Jessy/articles/1746337.html
轉載于:https://www.cnblogs.com/qhyuan1992/p/5385336.html
總結
以上是生活随笔為你收集整理的VC中的Unicode的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: unity3d-知识汇总
- 下一篇: 闲谈SQL脚本优化