1. 程式人生 > >各C/C++編譯器對wchar_t字元和字串的正確支援程度

各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相差不遠。