WIN32 的 _TCHAR 與 std::wstring 的問題
Posted on November 20th, 2007 at 3:28 by fr3@K

我知道很多人一直是這樣做的, 可是我從沒搞懂為什麼在 windows 平台上, 用上了 _TCHAR, _TEXT 再 define 個 _UNICODE. 或是用上了 whar_t 與 std::wstring. 就能算是 Unicode 化的程式?

Unicode 說穿了就是一種 數字到字元的對應. 而 UTF-8/UTF-16/UTF-32 等則是 Unicode 這種數字的編碼方式, 也就是同一個 (能對應 Unicode 字元的) 數字在不同的編碼下會是不同的 byte sequence.

在 WIN32 平台上, wchar_t 是個 16-bits 的型別.1 很明顯地, 它最多只能 (事實上應該也是) 對應到 Unicode 中的 UTF-16 編碼.

UTF-16 定義了約十一萬個字元.2 Wikipedia 也提到 UTF-16 是一種可變長度的編碼. 由此可見, 一個 WIN32 下的 whar_t 沒有辦法總是以一個 16-bits (最大值為 2^16 -1, 也就是 65535) 的數字來代表十一萬種字元.

由此可以知道一個 WIN32 的 wchar_t 是無法完全對應到一個 UTF-32 的 Unicode 字元. 所以類似下面的操作:


utf_32_char_t get_utf_32_char(const std::wstring& wstr, size_t n)
{
  assert(wstr.size() > n);
  return wstr[n];
}

並無法正確的對應到位於 n 位置的 Unicode 字元. 程式還是必須從 wstr 的頭掃描到第 n 個 Unicode 才能正確將一個 UTF-16 編碼的字元轉為 UTF-32 的字元. Windows 的 wchar_t 的優點或用處到底在那裡?

我看來是這只是偷懶的行為, 假裝每一個 WIN32 的 wchar_t 可以代表任意一個 UTF-16 的字元. 跟鴕鳥把頭躲進沙坑逃避現實的的行為沒什麼差異.

PS. 我對 Unicode 沒有特別研究, 上面應該有很多 Unicode 術語都用錯了. 但 concept 應該沒問題.


[Update: Nov 20, 2007 at 14:40]

感謝 Jeff 在回應裏面提到 Windows 的 wchar_t 是對應到 UCS-2, 而不是 UTF-16.3 這下子我可能有點搞懂了. UCS-2 的確就只能表達 Basic Multilingual Plane (BMP), 也就是 Unicode 中的 0×0000~0xFFFF. 以一個 16-bits 的整數是來表達 BMP 是 just make.

無法表達超出 BMP 的 Unicode, 這是 WIN32 的先天限制? 所謂的 Unicode API 也不真的那麼 Unicode, 是嗎?

好吧, 如果永遠活在 WIN32 的世界下這樣似乎也可行. 可是如果是從別的地方 (譬如透過網路) 傳過來一個非 BMP 的 Unicode 的字元時怎麼辦? 下面的 code 該怎麼寫?


wchar_t utf8_to_ucs2(const char* utf8)
{
  if(is_bmp(utf8) == true)
  {
    wchar_t usc2;
    // fine here, we just need an algorithm to transcode
    // a UTF-8 encoded BMP code point (character) to UCS-2
    return usc2;
  }
  else
  {
    // what goes here?
    // what to do if the code point is not a BMP?
  }
}

[Update: Sep 3, 2008 at 13:40]

Follow up is available in a more recent post - More on Unicoding.

  1. Default 似乎還不是 built-in/primitive, 而是個 得 include stddef.h/stdlib.h 或… 的 typedef []
  2. 另外在 rfc2781 的 Section 2 也說明了 UTF-16 無法表示值大於 0×10FFFF 的 Unicode []
  3. What is the difference between UCS-2 and UTF-16? []
del.icio.us:WIN32 的 _TCHAR 與 std::wstring 的問題 digg:WIN32 的 _TCHAR 與 std::wstring 的問題 spurl:WIN32 的 _TCHAR 與 std::wstring 的問題 newsvine:WIN32 的 _TCHAR 與 std::wstring 的問題 furl:WIN32 的 _TCHAR 與 std::wstring 的問題 Y!:WIN32 的 _TCHAR 與 std::wstring 的問題 黑米共享書籤:WIN32 的 _TCHAR 與 std::wstring 的問題 推推王:WIN32 的 _TCHAR 與 std::wstring 的問題
Previous Post
« 忙茫盲? «
Next Post
» 拒絕 Singleton »

3 Comments »

Comment #3987

wchar_t是「fixed size」,不同平台的大小不同。如win32是UCS2-LE,長2 bytes,而UNIX通常是UCS4,長4 bytes。所以,get_utf_32_char()是不會有問題的。

Comment by jeffhung — November 20, 2007 @ 12:30


Comment #3988

按照C++98,wchar_t是build-in type,但按照C99,wchar_t卻不是,故得#include某些header以取得typedef後的型別。由於一般C/C++ compiler都是做在一起的,故比較新的compilers會把wchar_t作成build-in/primitive type。

VC6不夠新,所以wchar_t不是build-in/primitive type,也因此用ostream時,comiler無法分辨wchar_t與short,而無法印出wchar_t字元。

也因為VC6的wchar_t不是build-in/primitive type,所以後來的MS C/C++ compilers,預設wchar_t也都不是build-in/primitive type。不過,可以在project setting裡調整,將wchar_t試作build-in/primitive type就是了。

Comment by jeffhung — November 20, 2007 @ 12:37


Comment #3990

Hi Jeff,

第二個回應的歷史我大致清楚.

針對第一個回應我還有接續的問題, 寫在 update 裏面. 感謝解惑.

Comment by fr3@K — November 20, 2007 @ 14:51


Comments RSS TrackBack URI

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>