刨根問底:C++中寬字元型別(wchar_t)的編碼一定是Unicode?長度一定是16位?

const_cast發表於2014-05-23

問題的起因是和一個朋友討論不同編碼的轉換問題,說到了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(也就是中文編碼),如果混用兩種方式編碼的字串,需要開發者手動去轉換。

相關文章