從C 與Unicode說開去

2021-04-15 06:53:10 字數 2058 閱讀 3960

以前遇到過這麼乙個問題,用c++序列化乙個wstring。程式很簡單,因為c++有wofstream:

std::wstring str   =   l"s";

std::wofstream ofile("f://test.txt");

ofile《我使用的編譯器是vc9,wchar_t是2位元組。那麼test.txt就應該是unicode的寬位元組,其大小應該是2位元組。但是實際的結果卻是1位元組,串並沒有按照寬位元組的方式儲存。這並非是編譯器的問題,其結果是符合c++標準的!其原因在於流在寫入的時候會呼叫codecvt這個模板類來對流的內容處理,而c++標準只規定了兩種codecvt:

codecvt

codecvt

模板的第乙個引數是內部型別,第二個是外部型別。

乍一看,如果使用預設的codecvt,輸出必然是char,也就是單位元組的。如果想要輸出寬位元組的流,必須得自行定義乙個什麼都不做的codecvt(其實這個理解是不對的,後面會解釋)。

把這個codecvt配置到locale裡面,再用locale配置流物件,那麼輸出就會是2位元組了。問題是輸出的字元是何種編碼呢?回答是:implement-dependent。編碼方式取決於你的編譯器中對於wchar_t這個型別是何種編碼的(注意wchar_t是標準所規定是keyword,如果你的編譯器很老比如vc6,那麼它會是乙個typedef),如果你的編譯器中wchar_t是2位元組,那麼編碼應該是ucs-2,如果是4位元組,那麼應該是ucs-4,輸出也就為4位元組,不再是2位元組了。不過我們可以肯定的是,此編碼不會是變長的編碼如utf-8(這是乙個變長的編碼以相容ascii,utf-8中的acsii部分的字元編碼是1位元組的。這麼做並不是資訊理論中的節省平均編碼長度,而僅僅是達到相容的目的)。關於編碼的知識網上有很多,不太了解的可以搜尋一下。

看似codecvt這個facet功能很弱,其實不然。codecvt中的內部型別和外部型別並非指的是輸入型別和輸出型別,乙個codecvt同樣可以實現unicode的輸出(boost中有個ucs-4到utf-8的轉換就是codecvt)。真正的編碼轉換部分是通過override其虛函式實現的,並不是指定模板引數實現的。模板引數的兩個type僅僅達到控制流的最小寫入字長,在理論上,實現合適的編碼轉換函式,codecvt就可以完成所有的編碼轉換,因為它處理的流都是最小長度,對於那些寬字元,只要有足夠的狀態記錄,就可以完成編碼轉換的目的(比如寫入多個char湊成乙個wchar_t,boost的那個codecvt就是這樣,通過寫入char來輸出utf-8。當然這也是最好的選擇,因為utf-8中有一位元組的字元。如果用wchar_t,在輸出那些乙個字元長度的字元時,反而麻煩)。

實際上c++本身或者說c++ standard並沒有提供編碼轉換的這麼乙個功能,他所提供的只是乙個框架,通過繼承codecvt,override他的虛函式去實現你自己需要的編碼轉換,使得你可以讓這個功能和其他c++庫函式結合起來。c++標準規定的兩個codecvt僅僅保證內部型別的流化,所謂內部型別就是c++語言本身使用的字元型別,它可以是單位元組的char也可以是多位元組的wchar_t。至於如何在不同編碼之間轉換需要你自己定義,預設的兩個codecvt只是ctype意義上的widen和narrow而已。

所以如果你需要這種編碼轉換功能,最好就是使用現成的庫(http://www.dinkumware.com/)或函式(iconv)。如果你夠強,自己繼承codecvt實現也是可以的:)

這是boost的ucs-4 to utf-8的文件

裡面的方法就是標準的c++方式,其中有一行是

std::locale utf8_locale(old_locale,new utf8_codecvt_facet);

意思是構造乙個locale,除了第二個facet,其他都保持預設。而第二個facet也就是你傳遞進去的那個實現了編碼轉換。facet通過引用計數來釋放,所以這種傳遞方式是沒問題的。其中的locale,facet都是c++標準庫的國際化元件,其組織結構是:locale是一組facet的容器,而codecvt又是facet的乙個子類。根據不同的功能,facet被分成幾組categories。具體的可以看下iso 14882 ,反正相關的資料非常少,cpl裡面都只有寥寥幾筆。

從PDF說開去

最近想研究一下pdf。pdf從ps脫胎而來,秉承ps強大的描述能力,以其精美的 效果,已幾乎成為internet時代的 標準文件格式 說pdf是 標準 可能有人不愛聽,見後文 如果軟體能夠支援自動輸出 匯出 為pdf格式文件,無疑軟體的專業化色彩會更濃一些。人之常理 你推出一種文件格式,使用的人 軟...

從時間說開去

非常羨慕那種需要很少睡眠,思維敏捷,做事雷厲風行的人。之所以羨慕,是因為我不具備。我做為乙個需要很多睡眠並且睡眠質量不高的人,做事也一般是三思而後行,遇事也慢人半拍,對於我這樣乙個人,怎樣合理安排時間就成了很大的問題。從小就喜歡利用一大片的時間,專注的去做一件事情。所以,在上了大學以後,看到我的同學...

從「盜版」說開去

發行了幾年的共享軟體 vb原始碼之友 終於被盜版了,雖然共享軟體沒有給我帶來讓人羨慕的財富,但是這幾年來也有不少的正版使用者群在默默的支援著我繼續推出我的軟體產品。我的心情其實很複雜,但卻沒有憤怒,在我腦中揮之不去的卻是 盜火 英雄普羅公尺修斯的偉大形象。想想看,如果不是盜版,作為普通的個人使用者,...