該死的BOM(byte-order mark)
2011-11-02 建立
最近接連遇到兩個奇怪的事情,一,在WINDOWS CYGWIN下可以編譯的C++代碼檔案,到了LINUX環境下使用GCC報存在游離的字元,導致編譯失敗。
(gcc編譯報錯:程式中有游離的‘\357’‘\273’‘\277’等 ,其原因有可能是
1,誤用了全形的符號和空格等,
2,BOM字元。)
二,在WINDOWS下正常解析的XML檔案在LINUX裝置上報“前置字元錯誤”。
最後發現這些問題都是微軟的BOM字元惹的禍。
什麼是BOM
BOM(byte-order mark),即位元組順序標記,它是插入到以UTF-8、UTF16或UTF-32編碼Unicode檔案開頭的特殊標記,用來識別Unicode檔案的編碼類別型。具體編碼如下表:
BOM Encoding
EF BB BF UTF-8
FE FF UTF-16 (big-endian)
FF FE UTF-16 (little-endian)
00 00 FE FF UTF-32 (big-endian)
FF FE 00 00 UTF-32 (little-endian)
微軟建議所有的 Unicode 檔案應該以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字元開頭。這作為一個“特徵符”來識別檔案中使用的編碼和位元組順序。BOM的本意不錯,但它並不是一個通用標準,從而導致了很多不相容的問題。
1. JDK1.5以及之前的Reader都不能處理帶有BOM的UTF-8編碼的檔案,解析這種格式的xml檔案時,會拋出異常:Content is not allowed in prolog.
2. Linux/UNIX 並沒有使用 BOM,因為它會破壞現有的 ASCII 檔案的文法約定。
3, 目前GCC編譯器不接受帶有BOM的原始碼檔案
不同的編輯工具對BOM的處理也各不相同。使用Windows內建的記事本將檔案儲存為UTF-8編碼的時候,記事本會自動在檔案開頭插入BOM(雖然BOM對UTF-8來說並不是必須的),但是其它編輯器的就不會這樣做,或者有專門的選項決定其行為。
當然解決BOM相容性這個問題也簡單,使用工具將帶有BOM的檔案儲存成不帶BOM的檔案,(例如可以使用Visual Studio進行轉換,選擇“檔案/進階儲存選項”,選擇儲存為 Unicode(UTF-8 無簽名) - 字碼頁65001 即可),或者自己使用工具刪除前置字元就可以了。如果是在程式中處理,可以以二進位方式開啟檔案,判斷一下是否存在BOM字元,然後再進行刪除或忽略BOM字元的操作。
最後,如果這時你的文檔為帶BOM的UTF-8檔案,使用的二進位編輯工具又恰好是ULTRAEDIT,很可能會碰到另外的奇怪的問題,將該檔案二進位顯示,會發現前導位元組為FFFE,以及文檔中的英文字元是兩個位元組,而不是UTF-8中的一個位元組,自己編寫一個小的二進位讀取工具會發現文檔並沒有問題,前導位元組是EFBBBF,英文字元也是一個位元組的。原因是預設配置的ULTRAEDIT對UTF-8進行了自動的轉換,轉為UNICODE LE格式,如果關閉其“自動檢測UTF-8格式資料”的選項,可以發現二進位顯示沒有問題,但文本顯示中的前導位元組和中文等字元會變成亂碼。因此該選項決定了ULTRAEDIT能夠正確顯示UTF-8檔案的文字格式設定還是二進位格式,一般我們還是選擇正確的文本顯示,因為大部分情況下需要的是文本編輯。但如果使用ULTRAEDIT刪除前置的BOM,需要暫時關閉該選項後再進行二進位編輯。
自動轉換為UNICODE LE的UTF8編碼XML檔案二進位顯示
不自動轉換的帶有BOM的UTF8編碼XML檔案二進位顯示
不自動轉換的不帶有BOM的UTF8編碼XML檔案二進位顯示