在 Standard C 裡頭,僅規定了我們可以利用 setlocale() 函式,來查詢或設定 C run-time 所用的,全域且唯一的 locale。然而,standard C 並沒有規定,傳進 setlocale() 的第二個參數,locale id,的格式與規定,而是交由各平台 (OS) 自訂。

所以問題來了,假若我們需要在程式裡 hard code 這個 locale id,以便傳給 setlocale(),那就會產生 portability 的問題。

解決辦法可以是,我們預先準備一張表格,訂定一套虛擬的 locale id 表格,在 compile-time 或 run-time 轉換成目標平台所用的 locale id。在 compile-time 我們可以利用 pre-processor 的 #define 來編寫這個表格,在 run-time 則建立 structure,linear-search 查表即可[1]。這樣子,我們就可以把 portability 問題,侷限在這個表格裡,且一併可達到 code-reuse 的目標。

因此,問題就轉換成了,我們怎樣建立與維護這個表格?這個表格不必太完整,但至少會用到的平台與 locale,都應該在裡面有資料。

今天就是碰到這個麻煩的問題。原本我僅為這個表,建立了正體中文,Windows、Linux/FreeBSD 的資料,因為大約也只會用到這麼多。更因為平常根本就是在正體中文裡頭跑,setlocale() 時直接就傳長度為零的字串 ("") 進去,使用環境設定的 locale,連查表都不需要了。然而今天因為必須讓程式可以在英文 Windows 上跑,而我們的資料又都是正體中文的,所以必須強制 hard code 設定成使用台灣的正體中文。

在我的電腦上跑,一切正常,因為當初的表格就是在我的電腦上建立的。但在同事的電腦上,就出問題了,程式無法接受轉換得來的,系統用的那個 locale id。

這可奇怪了,不都是正體中文的 windows 嗎?怎麼會同樣的字串,在不同的電腦上,setlocale() 的反應就不同?仔細一查並做實驗後的結果發現,我的電腦是 Windows XP SP2,而同事的電腦是 Windows 2000。在 Windows XP2 下,正體中文的 locale id 是 "Chinese_Taiwan.950",而在 Windows 2000 下,則是 "cht_taiwan.950"

這真是見鬼了!

而我做的這個虛擬 locale id 表格,是在 run-time 查詢 locale,在 compile-time 查詢平台種類,因為假定各個平台必須各自 compile 自己的執行檔版本,在 compile-time 查詢平台種類,可以將不相關的平台的資料去除。

所以這下麻煩了,根本不可能在 compile-time 就知道會在哪一版 Windows 上執行,只好上網找到這篇《How to determine which 32-bit Windows version is being used》,在 run-time 偵測 Windows 的版本,另外建個附表,專門在 Windows 下做轉換。


  1. 反正資料不多,用不到幾次,且都是在程式啟動時查詢。