終於進入最後一個主題了,對很多人來說這次的主題應該才是值得關注的重點吧!前面的主題都在告訴大家文字編碼的歷史以及規格,而這次的主題將是作者我在Unicode程式設計上對於文字編碼所遇到的問題、心得經驗、與對策;但也由於這次內容是以我的經驗與心得為主,因此難免較為主觀。
這次談論的所有話題將圍繞在Windows平臺上,不是因為這是擁有最多桌面用戶的作業系統也不是因為作者我喜歡Windows,而是因為幾乎只有在Windows上寫Unicode程式才會遇到一堆奇奇怪怪的問題;至於在其它的作業平臺上寫Unicode程式,通常來說大家只要像往常一樣的寫程式就可以了!
C/C++與Wide Character
有很多的人會把寬字元和Unicode畫上等號,事實上這是一個不正確的觀念(雖然絕大部分作業平臺上的寬字元的確是採用Unicode編碼)。C語言從C90開始加入了wchar_t這個基本型態,地位與char型態類似,但專用來表達8位元以上的寬字元。從語言標準上來看,這個型態遇到的多數問題之一就是型態尺寸的不統一,一個wchar_t變數所使用的位元組大小在不同系統平臺上是不一樣的,就筆者所聽過的作業系統就有1位元組、2位元組、和4位元組這三種。光是這樣的問題就足以讓寫資料傳輸程式和跨平臺程式的人煩惱了,有些人甚至稱呼wchar_t是C語言上一個錯誤的設計。
Windows上的Unicode程式設計
由於歷史的因素,Windows選擇了UTF-16LE做為系統核心的字元編碼機制,因此在Windows上要寫支援Unicode的程式就會需要使用到寬字元這種資料型別。使用寬字元來寫程式會面臨很多問題,這些問題以及因應對策將在下面一一說明。
使用寬字元型態改寫程式
第一步,你需要使用wchar_t來改寫你的程式,並且記得它佔用2位元組寬度(注意其他平臺不一定是這個值),最好是用它來取代所有原先使用char的地方,除非那個地方的char是真的被拿來處理位元組資料用的。如果你是個程式設計新手,這一個步驟其實沒什麼困難;但若你不巧是個已經擁有一堆寫好的程式的程式老手,也不要太過沮喪,因為最後你可能會認為這個步驟其實是所有問題當中最單純的,因為筆者我就曾經嘗試把自己寫的所有程式改成寬字元版!
使用寬字元版的標準函式庫
有些字串的處理我們並不會自己來做,而是呼叫標準函式庫的字串處理函式。這些標準函式絕大部分有寬字元版的函式可以用,比方說strlen對應wcslen、strncpy對應wcsncpy等等,總之就是strXXX要改成wcsXXX,至於C++的部份是std::string對應std::wstring、cout對應wcout等等。
然後你會發現有些函式並沒有寬字元對應版本,比方說用來開檔的fopen。如果你是個愛遵照語言標準的潔癖程式師,那麼這些問題可能會讓你想發火,因為C/C++標準對於寬字元的支援並不完整。但是如果你願意使用一些非標準的東西,則Windows提供了寬字元版的對應函式如_wfopen對應fopen、以及wmain對應main等等。
指令列模式對寬字元的支援很差
當你終於搞定了寬字元函式的呼叫後,你也許還會發現另一個令人吐血的事情,那就是作業系統本身對於寬字元IO的部份實在是慘不忍睹。下面這段是我用來測試的程式碼,有興趣的人可以在自己的電腦上跑跑看:
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#ifndef _WIN32
#error This program is design for Windows!
#endif
int main(int argc, char *argv[])
{
// Test sample :
// [test][測試][测试][テスト][테스트]
const char sample_utf8[] =
"[test]"
"[]"
"[]"
"[]"
"[]"
“