轉載自: http://www.ituring.com.cn/article/111027
問題的起因是和一個朋友討論不同編碼的轉換問題,說到了wchar_t的類型,朋友的看法是,wchar_t的編碼方式是utf-16,長度一定是16位的。我的看法不同,我認為wchar_t的長度和編碼方式都是編譯器和平台決定的,和語言沒任何關系。
后來這個朋友為了說服我,回家把C++ Primer給我搬出來了,還給我截了個圖(因為我沒這本書),在這本書第30頁有個表格,清楚地寫着wchar_t是unicode字符,而最小尺寸是16。既然“最小尺寸是16”了,那么其他尺寸的可能性就有了,但是編碼方式是怎么回事?因為憑我印象,貌似沒有任何文檔規定過寬字符的編碼方式,我想說服我朋友,但腦子里有沒有證據,不知道從何說起,因此回家仔細查了查資料,算是有了個了解。
1. 寬字符的編碼方式到底是誰定的?
這里有兩個選擇,要么是C++語言標准,要么是編譯器作者設計的;若是前者,則編碼方式就沒有異議了,任何平台、任何編譯器,都應該一樣;但若是后者,這就完全取決於編譯器制作者的想法了。那么,C++中,到底是什么情況?
我們可以翻閱下C++ ISO 2003的文檔,在3.91章第五條,清楚地寫着wchar_t的定義如下:
Type wchar_t is a distinct type whose values can represent distinct codes for all members of the largest extended character set specified among the supported locales (22.1.1). Type wchar_t shall have the same size, signedness, and alignment requirements (3.9) as one of the other integral types, called its underlying type.
從這段描述中可以得出幾個結論:1. wchar_t是用來存儲所有支持區域的字符的;2. wchar_t的底層存儲方式是整形,本質上也就是個整形。
其實不論是char還是wchar_t,底層的存儲都是整形,因此即使你存了個字符進去,仍然會以整形的形式存儲,所以這里面涉及到了一個轉化問題,也就是我們所談的字符編碼。
而編碼方式在以上的C++ ISO文檔里並找不到文字說明,因此,可以確定,編碼方式是編譯器實現的,並且是沒有標准的。
那么,就引出了第二個問題。
2. 編碼方式有幾種?寬字符存儲的長度一樣嗎?
先從char說起,char型的常見編碼方式是ASCII,ASCII編碼是一種基於8位二進制數的字符編碼算法,是美國ANSI制定的一種單字符編碼方案,能表示256種可能的字符,常見的字母、符號、鍵盤指令等,全能用ASCII碼表示,而由於ASCII碼是基於8位的編碼,因此用這種算法的編譯器,char類型都占8位。請注意因果關系,是因為用了ASCII,所以char才是8位,而不是char是8位,所以采用ASCII。
同理可適用於wchar_t類型。
wchar_t的出現,是出於程序兼容多語言的需求,因為在很多語言中,字符的數量遠遠大於256,因此需要把原字符進行擴容,必須能表示更多的字符類型。因此wchar_t出現了,wchar_t全稱是wide character type,也就是寬字符。最常見的寬字符編碼方式就是unicode了,utf-16和utf-32都是unicode編碼。wchar_t也主要以這兩種方式實現。
utf-16是完全基於ucs-2的,但存儲的方式分為Big Endian和Little Endian,區別在於存儲的順序,比如字符A用utf-16BE的方式表示是0x0041,用utf-16LE的方式表示則是0x4100,我在我的機器上試了下,用VC10編譯器,wchar_t的編碼方式是utf-16BE。而在gcc下是utf-32BE。
關於各種的編碼算法,資料繁多,我就不多說了。
但這個問題是解決了,那就是,wchar_t的目的是編碼並存儲所有字符集,編碼方式和存儲空間大小和語言無關,只和編譯器有關,因此說wchar_t的編碼方式是unicode是錯的。C++ Primer上的描述也是不准確的。
哦,對,最后補充一下,unicode是兼容ASCII的,ASCII所能表示的字符,用unicode編碼可以得出一樣的值。但不兼容GBK(也就是中文編碼),如果混用兩種方式編碼的字符串,需要開發者手動去轉換。