C++字符串之一(字符表示)
在C++中有兩種類型可以用于表示字符,char和wchar_t。
但是字符串格式的標準卻有很多種,如ASCII,UTF8,UTF16,UTF32等等。字符串的格式和char/wchar_t 的關系是什么呢?
首先要理解Unicode和UTF-8的關系,可以參考我轉帖的文章:http://www.cnblogs.com/whyandinside/archive/2012/02/05/2338841.html?
額外還有幾個問題需要解決:
1. UCS-2、UCS-4、BMP
UCS有兩種格式:UCS-2和UCS-4。顧名思義,UCS-2就是用兩個字節編碼,UCS-4就是用4個字節(實際上只用了31位,最高位必須為0)編碼。下面讓我們做一些簡單的數學游戲:
UCS-2有2^16=65536個碼位,UCS-4有2^31=2147483648個碼位。
UCS-4根據最高位為0的最高字節分成2^7=128個group。每個group再根據次高字節分為256個plane。每個plane根據第3個字節分為256行 (rows),每行包含256個cells。當然同一行的cells只是最后一個字節不同,其余都相同。
group 0的plane 0被稱作Basic Multilingual Plane, 即BMP。或者說UCS-4中,高兩個字節為0的碼位被稱作BMP。
UCS-4的BMP去掉前面的兩個零字節就得到了UCS-2。在UCS-2的兩個字節前加上兩個零字節,就得到了UCS-4的BMP。而目前的UCS-4規范中還沒有任何字符被分配在BMP之外。
?
2. UTF-16是如何表示Unicode的?
在基本多語言平面內定義的符號((Basic Multilingual Plane, BMP),或稱第零平面(Plane 0)),使用2個字節表示,在此之外的字符(其他平面內的字符),則使用4個字節表示。由於第零平面內,從0XD800到0XDFFF之間的區段是沒有使用的,因此可以利用0XD800-0XDFFF之間的值來對輔助平面的字符進行編碼。?
其編碼方法是:
UTF-16可看成是UCS-2的父集。在沒有輔助平面字符Mapping of Unicode character planes(surrogate code points)前,UTF-16與UCS-2所指的是同一的意思。但當引入輔助平面字符後,就稱為UTF-16了。現在若有軟件聲稱自己支援UCS-2編碼,那其實是暗指它不能支援在UTF-16中超過2bytes的字集。對於小於0x10000的UCS碼,UTF-16編碼就等於UCS碼。
?
3. wchar_t是UTF-16嗎?他們之間的關系是什么?
wchar_t在不同的平臺上size是不一樣的,MSVC它是2字節的;而在Linux上它就是4字節了。wchar_t在Windows可用于存儲UTF-16的字符;而在Linux上往往用于存儲UTF-32在字符。
比如:Windows上的函數MultiByteToWideChar是這樣描述的:Maps a character string to a UTF-16 (wide character) string. The character string is not necessarily from a multibyte character set.
int MultiByteToWideChar( __in UINT CodePage, __in DWORD dwFlags, __in LPCSTR lpMultiByteStr, __in int cbMultiByte, __out LPWSTR lpWideCharStr, __in int cchWideChar );
Different compilers and platforms define wchar_t differently, because they use different Unicode encoding techniques. On Windows/Visual C++ for instance, wchar_t is a 16 bit type, suitable for UTF-16. On GCC/Linux for instance, wchar_t is a 32 bit type, suitable for UTF-32.
Depending on your requirements (speed, memory usage), you should pick an internal format that suits the platform. On Windows it might be UTF-16, and on Linux it might be UTF-32. That way you won't have to transcode strings all the time, just to make simple platform-defined operations on them (wcslen(), wcscmp(), etc).
For external formats (text files, etc), I tend to use UTF-8. The reason is that files are considerably smaller if they contain text in a western language. Another benefit is that you don't have to consider endianess in UTF-8, which makes the chance of errors (on your or some other's part) less likely.
4. SBCS、DBCS和MBCS?
SBCS、DBCS和MBCS分別是單字節字符集、雙字節字符集和多字節字符集的縮寫。SBCS、DBCS和MBCS的最大編碼長度分別是1字節、兩字節和大于兩字節(例如4或5字節)。例如:代碼頁1252 (ANSI-拉丁文 I)是單字節字符集;代碼頁936 (ANSI/OEM-簡體中文 GBK)是雙字節字符集;代碼頁54936 (GB18030 簡體中文)是多字節字符集。單字節字符集中的字符都用一個字節表示。顯然,SBCS最多只能容納256個字符。
雙字節字符集的字符用一個或兩個字節表示。那么我們從文本數據中讀到一個字節時,怎么判斷它是單字節字符,還是雙字節字符的首字符?答案是通過字節所處范圍來判斷。例如:在GBK編碼中,單字節字符的范圍是0x00-0x80,雙字節字符首字節的范圍是0x81到0xFE。我們順序讀取字節數據,如果讀到的字節在0x81到0xFE內,那么這個字節就是雙字節字符的首字節。GBK定義雙字節字符的尾字節范圍是0x40到0x7E和0x80到0xFE。
GB18030是多字節字符集,它的字符可以用一個、兩個或四個字節表示。這時我們又如何判斷一個字節是屬于單字節字符,雙字節字符,還是四字節字符?GB18030與GBK是兼容的,它利用了GBK雙字節字符尾字節的未使用碼位。GB18030的四字節字符的第一字節的范圍也是0x81到0xFE,第二字節的范圍是0x30-0x39。通過第二字節所處范圍就可以區分雙字節字符和四字節字符。GB18030定義四字節字符的第三字節范圍是0x81到0xFE,第四字節范圍是0x30-0x39。
?
5. UTF-8 可以和ANSII兼容;而UTF-16和UTF-32不可以。
6. 字符串有兩種存儲方式:保存總長度和結束符。結束符是最常使用的,比如char字符串使用\0來判斷字符串結尾;而wchar的字符串使用’\0\0’來判斷字符串結尾。 保存總長度也是一種方式,在COM中BSTR就是這樣使用的。
BSTR(Basic STRing)實際上是類Pascal字符串,在BSTR的前4個字節保存了字符串長度,所以BSTR內部可以包括\0,它也不是靠\0來判斷字符串結尾的。BSTR在c/c++中的定義實際上是wchar_t*,但因為BSTR是依靠前4個字節來判斷字符串長度的,所以它的分配和釋放都不同于普通的字符串,需要通過::SysAllocString和::SysFreeString等函數來分配和釋放。
?
?
參考:
1.?http://blog.sina.com.cn/s/blog_4c860d7e0100hzzj.html
總結
以上是生活随笔為你收集整理的C++字符串之一(字符表示)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: L型代码结构案例:Link访问权限(上)
- 下一篇: Redis在Windows+linux平