TAG

首都機能移轉 (2) 歌詞 (2) 靠北文 (40) 戲言 (30) 糟糕 (7) ACG (23) Assembly (2) Boost (2) C (31) C++ (69) CMake (4) CSIE (67) Debian (34) Design_Pattern (2) Django (1) Eclipse (1) en_US (13) FFmpeg (3) FoolproofProject (26) FreeBSD (2) Git (4) GNU_Linux (65) IDE (5) Java (11) JavaScript (19) KDE (15) Khopper (16) KomiX (3) Kubuntu (18) Life (1) Lighttpd (2) Mac_OS_X (2) Opera (1) PHP (2) PicKing (2) Programing (21) Prolog (1) Python (7) QSnapshot (2) Qt (30) Qt_Jambi (1) Regular_Expression (1) Shell_Script (7) Talk (98) VirtualBox (7) Visual_Studio (13) Windows (18) zh_TW (36)

2009年2月9日 星期一

該死

我實在不知道該怨恨誰了,就讓我恨天吧...(?)
故事的開頭,是在我想把程式port到Windows的時候發生的。
首先我遇到了TR1和C99名稱缺省的問題,沒關係,我知道每次都要跟上標準很累,VC沒有<cstdint>,gcc也沒實作std::tr1::regex,一人一次很公平,打平了,還好我還有Boost,不怕你。
然而沒想到魔王其實不在這裡,而是Unicode。
先簡單的介紹一下一般處理系統字串的方法好了。
大家都知道早期各國為了顯示自己的文字,定了各種了不起的編碼方式來對應字型,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。
這還不是最糟糕的。
Linux的系統函式都沒有提供wchar_t的版本,因為現在系統上的編碼都是用UTF-8,就算用locale的編碼也不會漏失字元。
但是Windows就提供了另一套w開頭的API,以提供wchar_t的版本,同時系統函式分成兩系,一是W結尾,使用wchar_t,一是A結尾,使用char,而且要編成本地編碼。
於是當某個你碰不到的程式碼內部使用fopen時,在Windows上你一點辦法都沒有,根本不能讀取non-ascii的路徑。

4 則留言:

  1. 編碼果然是寫程式最大的災難之一...

    回覆刪除
  2. 運氣好的話, 可先把你的 wide (utf-16) path 轉成 multi-byte-string path 再丟給那個碰不到的 fopen.

    不過我想你已經知道了, 這只有在組成你的 wide path 的 code point 能夠對應到 global locale 的 charset 的時候才行得通...

    回覆刪除
  3. 我有試過:
    1.UTF-8 -- 失敗
    2.locale encoding -- 失敗
    3.直接wcstombs -- 還是失敗

    現在我真的不知道要怎麼讓它動了...
    目前想到可行的方法只有兩種:
    1.挖出那個可以開fd的版本
    2.把原始碼搞出來自己hack

    但是我真的很希望fopen可以直接讀取locale encoding的path...

    另外, 我有試著用locale encode過的path去寫檔, 路徑是正確的
    完全無法理解....

    回覆刪除