各C/C++編譯器對wchar_t字元和字串的正確支援程度
傳統的C風格的字串是以字元 '/0 '為結尾的一系列位元組的集合,其一個單元為char型別,可以儲存世界上的幾百種不同的字符集,包括ASCII、ISO-8859、GBK、BIG-5、SHIFT-JIS、UTF-8等等。通常這些字符集都是相容ASCII字符集的。我們可以把這些相容ASCII字符集統稱為ANSI字符集。正因為各種不同的字符集的存在,所以在實際的使用中會產生各種缺字和亂碼的現象。
Unicode是包含世界上各種語言和符號的編碼。
在實際應用中,Unicode以UTF-8和UTF-16、UTF-32這三種形式存在,這三種形式都可以完美地表示Unicode的各個碼位。
例如:中文的 "中 "字,其Unicode碼位為U+4E2D,用UTF-8用三個8位的位元組來表示為:0xE4 0xB8 0xAD,UTF-16則使用一個16位的整數0x4E2D來表示,UTF-32則使用一個32位的整數0x00004E2D來表示。(當字元碼位大於0xFFFF時,UTF-8要用四個8位的位元組來表示,UTF-16需要使用2個16位整數來表示)
UTF-16與UTF-32相比,UTF-16顯得更加簡潔。Windows下普遍使用UTF-16,而Linux和其它Unix類的系統由於歷史上的設計原因,則比較傾向於使用UTF-8和UTF-32這兩種傳輸方式。
C/C++標準均已經提供了wchat_t關鍵字來實現對Unicode的支援,而且wchat_t型別只用於Unicode編碼。在Windows平臺下,wchat_t型別是16位的;而在Linux下,wchat_t型別是32位的。
下面以Windows x86平臺下為例子,說明wchar_t字串在記憶體中的儲存形式:
例如下面一個UTF-16字串:
wchar_t str[]=L "中文 ";
上面是一個UTF-16的字串,是分別由0x4E2D,0x6587,0x0000所組成的串。因為x86的CPU是低位元組在前的(Little Endian),所以該wchar_t串在記憶體中的儲存為:2D 4E 87 65 00 00。
Unicode在C/C++中就是這麼簡單的表示用法,在某些的C/C++編譯器中,卻不能完善支援,下面就列舉各C/C++編譯器對wchar_t字元和字串的支援程度:
(1)Visual C/C++
Visual C/C++的編譯器對Unicode的支援是最完美的,Microsoft是Unicode的創造者之一,也是極力推薦使用Unicode編碼的公司。
Visual C/C++除了完美支援wchar_t型別外,Visual C++ 7.0或者更新版本的編譯器還可以接受UTF-8/UTF-16編碼格式的原始碼檔案。
(2)Borland C/C++
Borland C/C++的編譯器對Unicode的支援也是完美的,從1994年的Borland C++ 4.5開始,Borland C/C++的編譯器就能正確處理wchar_t字元和字串。
C++Builder 6.0的編譯器還添加了 -CP 引數來支援各種不同Codepage的原始碼。
C++Builder 2006還可以支援UTF-8編碼格式(帶BOM)的原始碼檔案,但是不支援UTF-16編碼格式的原始碼檔案。
(3)gcc
GNU C/C++編譯器也可以正確支援wchar_t字元和字串,但是原始碼的儲存格式必須符合下面條件:
一、原始碼檔案的儲存編碼必須是UTF-8
二、UTF-8編碼格式的原始碼檔案,不能有BOM標誌頭。
只有原始碼檔案符合上面兩個條件,gcc才會正確支援wchar_t字元和字串。如果不符合上面兩個條件的話,有可能會編譯出錯,有可能會產生錯誤的wchar_t字元和字串。
gcc在Windows平臺下,wchar_t是16位型別,在Linux平臺下,wchar_t是32位型別。
另外,GCC提供了以下的引數開關來支援其它文字編碼的原始檔:
(a)-finput-charset=charset
gcc在預設情況下,總是假設原始碼的編碼是UTF-8,如果是其它編碼的原始碼檔案, 原始碼裡面又用到了wchar_t的型別,則可以使用-finput-charset=charset這個引數來實現。
例如通常使用GBK編碼的原始碼可以假如引數:-finput-charset=GBK
(b)-fwide-exec-charset=charset
預設情況下,gcc在Windows平臺下,寬字串串常量的每個字元是16位UTF-16型別,在Linux平臺下,寬字串串常量的每個字元是32位UTF-32型別, 使用這個引數,可以改變寬字串串常量的型別。
例如在x86的機器環境,Linux作業系統下,要使例如 L"漢字" 編譯後儲存為UTF-16的字串,則可以使用 -fwide-exec-charset=UTF-16LE
(4)Digital Mars C/C++
Digital Mars C/C++ 的前身是Symantec C/C++。
Digital Mars C/C++也可以正確支援wchar_t字元和字串。
但是Digital Mars C/C++不能接受UTF-8(帶BOM)、UTF-16編碼格式的原始碼檔案。
(5)OpenWatcom C/C++
OpenWatcom C/C++不支援wchar_t字元和字串。
雖然OpenWatcom C/C++在處理wchar_t字元和字串時,不會編譯錯誤,但是所產生的wchar_t字元和字串確實錯誤的。
OpenWatcom C/C++也不能接受UTF-8(帶BOM)、UTF-16編碼格式的原始碼檔案。
OpenWatcom可以說是對Unicode支援最差的編譯器。
(6)Intel C/C++
和Visual C++差不多。
是否支援UTF-8/UTF-16編碼格式的原始碼檔案,本人則沒有進行詳細的測試。
(6)PGI C/C++
沒有對這個編譯器進行詳細的測試,但是PGI C/C++的前端是來自gcc,理論上應該跟gcc相差不遠。