我實在不知道該怨恨誰了,就讓我恨天吧...(?)
故事的開頭,是在我想把程式port到Windows的時候發生的。
首先我遇到了TR1和C99名稱缺省的問題,沒關係,我知道每次都要跟上標準很累,VC沒有<cstdint>,gcc也沒實作std::tr1::regex,一人一次很公平,打平了,還好我還有Boost,不怕你。
然而沒想到魔王其實不在這裡,而是Unicode。
首先我遇到了TR1和C99名稱缺省的問題,沒關係,我知道每次都要跟上標準很累,VC沒有<cstdint>,gcc也沒實作std::tr1::regex,一人一次很公平,打平了,還好我還有Boost,不怕你。
然而沒想到魔王其實不在這裡,而是Unicode。
先簡單的介紹一下一般處理系統字串的方法好了。
大家都知道早期各國為了顯示自己的文字,定了各種了不起的編碼方式來對應字型,Big5的許功蓋就是這段歷史下的偉大人物,大概比踢牙齒老奶奶這位史詩級人物還要再個高一級左右。
夫天下大勢,分久必合合久必分,某個大有為的組織看不慣這種戰國亂象,於是制定了Unicode的編碼標準,以對應全人類的偉大文化產物,又生出了各種對應Unicode的編碼方式,希望能夠平息亂碼之亂。要注意的是,編碼標準和編碼方式不同,每個文字在Unicode裡只有一種編碼標準,再根據各種不同的編碼方式,比方說UTF-8或UTF-16,UCS4等編成不同的編碼。
大家都知道早期各國為了顯示自己的文字,定了各種了不起的編碼方式來對應字型,Big5的許功蓋就是這段歷史下的偉大人物,大概比踢牙齒老奶奶這位史詩級人物還要再個高一級左右。
夫天下大勢,分久必合合久必分,某個大有為的組織看不慣這種戰國亂象,於是制定了Unicode的編碼標準,以對應全人類的偉大文化產物,又生出了各種對應Unicode的編碼方式,希望能夠平息亂碼之亂。要注意的是,編碼標準和編碼方式不同,每個文字在Unicode裡只有一種編碼標準,再根據各種不同的編碼方式,比方說UTF-8或UTF-16,UCS4等編成不同的編碼。
那麼我們在程式裡是怎麼處理各種不同的輸入和輸出呢?
最常用的方法就是,把輸入字串解碼成Unicode字串,如此一來就可以在程式裡方便地處理字串,在輸出時再編碼成需要的輸出字串。
那要怎麼存Unicode字串呢?C和C++都提供了wchar_t來存寬字元,你可以用它來存放Unicode化過的字元。但是有趣的地方也在這裡,Windows和其他系統的wchar_t的寬度是不一樣的,Windows是2 bytes,Linux等是4 bytes,因此在Windows上你可能要選擇UTF-16,而在Linux上要用UCS4。
最常用的方法就是,把輸入字串解碼成Unicode字串,如此一來就可以在程式裡方便地處理字串,在輸出時再編碼成需要的輸出字串。
那要怎麼存Unicode字串呢?C和C++都提供了wchar_t來存寬字元,你可以用它來存放Unicode化過的字元。但是有趣的地方也在這裡,Windows和其他系統的wchar_t的寬度是不一樣的,Windows是2 bytes,Linux等是4 bytes,因此在Windows上你可能要選擇UTF-16,而在Linux上要用UCS4。
這還不是最糟糕的。
Linux的系統函式都沒有提供wchar_t的版本,因為現在系統上的編碼都是用UTF-8,就算用locale的編碼也不會漏失字元。
但是Windows就提供了另一套w開頭的API,以提供wchar_t的版本,同時系統函式分成兩系,一是W結尾,使用wchar_t,一是A結尾,使用char,而且要編成本地編碼。
Linux的系統函式都沒有提供wchar_t的版本,因為現在系統上的編碼都是用UTF-8,就算用locale的編碼也不會漏失字元。
但是Windows就提供了另一套w開頭的API,以提供wchar_t的版本,同時系統函式分成兩系,一是W結尾,使用wchar_t,一是A結尾,使用char,而且要編成本地編碼。
於是當某個你碰不到的程式碼內部使用fopen時,在Windows上你一點辦法都沒有,根本不能讀取non-ascii的路徑。
編碼果然是寫程式最大的災難之一...
回覆刪除運氣好的話, 可先把你的 wide (utf-16) path 轉成 multi-byte-string path 再丟給那個碰不到的 fopen.
回覆刪除不過我想你已經知道了, 這只有在組成你的 wide path 的 code point 能夠對應到 global locale 的 charset 的時候才行得通...
我有試過:
回覆刪除1.UTF-8 -- 失敗
2.locale encoding -- 失敗
3.直接wcstombs -- 還是失敗
現在我真的不知道要怎麼讓它動了...
目前想到可行的方法只有兩種:
1.挖出那個可以開fd的版本
2.把原始碼搞出來自己hack
但是我真的很希望fopen可以直接讀取locale encoding的path...
另外, 我有試著用locale encode過的path去寫檔, 路徑是正確的
完全無法理解....
我說的是寫入新增的檔案
回覆刪除