研究過 BBS source 的人應該都知道一個很有名的 BIG5 衝碼問題:"壞蛋許\\n"。由於 GCC 跟 VC6 在此處的作法不太一樣。對於 GCC 而言,輸入的程式碼,是一串 bytes,而 VC6 在中文 Windows 裡,則是會把輸入的程式碼,看做是一串 big5 字元,而不只是一串 bytes 而已,所以必須用醜陋的 #ifdef 法,特別為含有「許功蓋」的 string literals[1],各寫一個版本,像這樣:
#if (ADK_COMPILER == ADK_COMPILER_MSC)
printf("壞蛋許\n");
#else if (ADK_COMPILER == ADK_COMPILER_GCC)
printf("壞蛋許\\n");
#endif
把輸入的程式碼,看做是一串 bytes,因此,含有反斜線的「許」字放在 string literals 裡,就必須多加一個反斜線在後面。這樣其實很難用,我常為了要讓程式可以同時 porting 在奮鬥。不過,難用歸難用,但按照 C++98,GCC 的作法,才是比較對的 (雖然也沒有算是完全正確)。
在 Standard C++ 2.2.1 裡指出:
The basic source [...]
我總‧是‧說,FreeBSD 5 比 FreeBSD 4 好很多,因為 wide character/string support 在 FreeBSD 4 上,根本就是殘廢狀態。但到底差了多少呢?我一直也都說不上來。
今天看到 ijliao's blog 的這篇《FreeBSD 官方網頁改版》,跑去參訪了一下新版的 FreeBSD.org,結果逛到 FreeBSD C99 and POSIX® Conformance Project,從最後一個表「Wide Character/String Support」裡,終於知道 FreeBSD 4 的 wide character/string support,到底有多殘廢。
看著整排的 N/A,心中不禁感嘆,還好我在一年前就毅然決然地 migrate 到 FreeBSD 5 了,要不然開著殘廢破車寫一大堆需要 i18n 的程式,肯定痛苦要死。
記錄一下從 VB 呼叫用 VC 製作的 DLL 的心得:
1. 使用 __stdcall 搭配 .def 檔製作 DLL VC 製作 DLL 的方法。
有兩種方法。
第一種方法是使用 __declspec(dllexport) 宣告要 export 的函式,讓 VC 幫忙製作 stub library,這時預設使用的 calling convension 是 __cdecl。這樣宣告後,VC 會產出 libFoo.dll 與 libFoo.lib 兩個檔案,其中後者就是所謂的 stub library,VC 會自動於 stub library 裡製作對應到 libFoo.dll 裡 _funcFoo 這個 symbol 的 __imp_funcFoo。
這個方法的好處是,在 VC 裡的 project 有 dependency 時,會自動 [...]
用 VB6 呼叫用 VC6 寫的 DLL,檔案確實有更新且擺放在 VB 的 project 目錄下了,函式也確實地用 __stdcall 與 def 檔宣告了,但就是會跑出
Error 53: File not found libFoo.dll
的訊息。
後來查到《Bugs: Error 53 when calling functions from custom DLL》這個網頁才知道,是 libFoo.dll 所需要的 libBar.dll 忘了複製過來的緣故。 不過,這什麼鳥蛋 error message 啊,一點提示效果都沒有,難怪查到的網頁要用 Bugs 開頭。
看了一下 MSDN 裡 VB6 的 error code 列表,少的可憐。寫 VB 真的要自求多福才行。
為了要抓 MAC address,用 GetAdaptersInfo() 興高采烈地把程式寫好之後,卻發現因為少了 iphlpapi.h 和 iphlpapi.lib 而無法 compile,這才知道必須要裝 Microsoft Platform SDK 才能夠用舊版 Visual C++ 推出時還沒有出現的 Windows 的新功能。
好死不死地,也許是為了推廣 .Net,Microsoft 老早就停止了對 Visual Studio 6 的支援,所以現在 Microsoft 網站上 officially 可以抓到的 Platform SDK,只有最新版的 Windows® Server 2003 SP1 Platform SDK。可是,網頁上卻寫著:
Development Tools. To build the C/C++ samples, you must have a C/C++ compiler. If you are using Microsoft Visual [...]
剛去看 Boost 網站,發現整個網站改版,換上了上次 Boost logo competition 的第一名的新 logo,然後赫然發現 Boost 1.33 也一併 release 了。以下是 release announcement,我把我比較感興趣的部分,以藍色加底線的形式 (不能點,以後有時間再撰文討論) 表示:
Boost 1.33.0
New Libraries
Iostreams Library: Framework for defining streams, stream buffers and i/o filters, from Jonathan Turkanis.
Functional/Hash Library: A TR1 hash function object that can be extended to hash user defined types, from Daniel James.
Parameter Library: Write [...]
在硬碟裡發現這篇去年寫的舊文,放到 blog 上備查。
單純轉換
我們大致上會需要以下幾種 encoding 之間的相互轉換。
BIG5
GB2312
UTF-8
Unicode
wchar_t
其中,Unicode 指 UCS2-LE、UCS2-BE、UCS4-LE 或 UCS4-BE 等 encoding,而 wchar_t 則視平台而定。純粹的 encoding 互轉的話,由於 Unicode 號稱能納萬物,所以建議的轉換程序如下:
BIG5 <-> Unicode/UTF-8
BIG5 -> Unicode/UTF-8 -> GB2312
GB2312 <-> Unicode/UTF-8
GB2312 -> Unicode/UTF-8 -> BIG5
而若以「外部檔案用與平台無關的 encoding 如 BIG5、GB2312 或 UTF-8,內部程式使用 wchar_t 執行演算法」的準則來看的話,我們會需要以下幾種 encoding 轉換:
BIG5 <-> wchar_t
GB2313 <-> wchar_t
UTF-8 <-> wchar_t
進階轉換
另外,除了純粹的 encoding 轉換之外,也許有時還會需要更進一步的轉換機制:
處理非一對一對應:好比在繁簡體中文之間,有所謂一對多的困擾,一個簡體字,可能對應到多個繁體字。若有能夠依據前後文決定如何選取一對多的多個字中的哪一個字,這樣子的轉換會比單純的 encoding 轉換還要來得精準。
詞彙轉換:能轉換同義異形的兩岸詞彙用語。
轉換工具:libiconv
在 UNIX 上,首推 iconv,這是 libiconv 的 command-line [...]
剛剛寫了一個簡單至極的小程式,是的,就是那個第一千次 commit 的 class,::mmi::util::version。這個 class 把三個 uint32_t 包起來,分別賦予 major version number、minor version number 以及 revision number 這三個意義。可是,想 porting 回 GCC 時,竟然產生 compilation error。錯誤訊息是這個樣子的:
c++ -Wall -I./include -g `env PKG_CONFIG_PATH=. pkg-config --define-variable=prefix=. --cflags libMMI` -o src/mmi/util/version.o -c src/mmi/util/version.cpp
src/mmi/util/version.cpp:72: error: expected unqualified-id before '(' token
src/mmi/util/version.cpp:72: error: abstract declarator `uint32_t' used as declaration
src/mmi/util/version.cpp:72: error: `uint32_t mmi::util::version::$_12' is not a [...]
libMMI 是我在工作上,順帶寫的一個程式庫。目的在累積 domain independent 的 know-how,以加速日後程式的建構。發展準則有:
Incremental construction - 有用到的 feature 再加,慢慢累積。
Homogeneous across languages - 橫跨若干 programming language,不同於 C# 的 CLI,只求用法、API 長相差不多就好。目前用到的有 C/C++、Perl、PHP、SH 等程式語言。
Cross-platform if possible - 盡可能地隱藏 cross-platform 的細節,目前可以橫跨 FreeBSD/Win32 以及 GCC3/MSVC6。不過因為 incremental construction 的發展準則,尚未 porting 的功能,會產生 pre-processor-time 或 run-time error。
Privode both C/C++ interface if possible - 盡可能地為 C/C++ 推出不同介面,對應功能的版本。
就在剛剛,我做了第一千次的 commit。因此趕緊來賽豬公一下:
SHELL> svn log -r 1 [...]
在工作上,經常會碰到萬碼奔騰的狀況,常搞的我一個頭兩個大,還好經過一年多的努力,處理 i18n 的程式庫大致有了個基礎,雖不完整,但也堪用。我有試著讓這堆 i18n 的程式儘可能地一致有條理,但邊造槍邊上戰場,還是有很多地方雜草叢生,旁枝錯節,無法達到完美和諧。所以我也只能盡量,將「萬碼奔騰」化約為「五碼諧和」,便是其中的一個嘗試。
世界上的語言千萬種,應用在電腦上,各家都要有自己的一套,因而造成了「萬碼奔騰」的現況。雖然 Unicode 包容萬碼的理想極其崇高偉大,但是革命尚未成功,同志仍須努力。一天這個世界還不能大一統,身為師程工的我們,就必須要身先士卒,代替普羅大眾,面對萬碼侵襲。
還好,我們有「化約」這個武器,可以化繁為簡,萬宗歸五,將「萬碼」化約成「五碼」,挑出重點,各個擊破。哪五碼?RAW、MBCS、WCCS、U8CS 以及 CLCS 這五碼,各有各的花名,招式相同的,大家一條褲子一起穿,招式不同的,那就各顯本事,各展奇才。口說無憑,有表有真相。
編碼
字元
字串
說明
花名
型別
花名
型別
RAW
-
char
str
char*
無招勝有招,赤裸裸的 bytes 專門演出無碼劇。本應使用 byte_t 為其型別,但為與大多數的舊有 C 程式介面相容,故仍沿用 char。
MBCS
mbc
char*
mbs
char*
用多個 bytes 表達一個 character 的編碼形式。某些 MBCS 需要 shift-state 的支援。對 C/C++ 來說,MBCS 對應到目前唯一的 global locale。
WCCS
wcc
wchar_t
wcs
wchar_t*
由 OS/Compiler 廠商決定的固定長度 Unicode 編碼,無法跨平台,兼有包容與速度的優勢。
U8CS
u8c
char*
u8s
char*
即 UTF-8,為近年流行的跨平台之不固定長度 Unicode 編碼,未來的烏托邦,便是只剩下 WCCS 與 U8CS 這兩種碼的大一統世界。雖然現在還不是,但我們必須向著這個方向走。
CLCS
lcc
byte_t*
lcs
byte_t*
CLCS 為 Custom Locale Character Set 的縮寫,即指定 locale 的編碼方式。當其他四碼都不行時,就只有靠他了。
為了分辨彼此,各招的名稱,必須內含各碼的花名。舉例來說,光就「長度」這一項,就可以分化成三個變化:有多少個 bytes、有多少個 characters 以及畫在終端機螢幕上時,佔用多少個基本寬度。將上表套用這三個變化,就成了以下各招的招型:
有多少個 bytes:除了 RAW [...]