本業の方で障害発生ガッシボッカなので、あんま長文書いてる時間ないので細切れにね。

wchar_tは決してUnicode(UCS2/4)ではないよというお話の第1回目。

そんなん 仕様を読めば一目瞭然です罠。

wchar_t Integer type whose range of values can represent distinct wide-character codes for all members of the largest character set specified among the locales supported by the compilation environment: the null character has the code value 0 and each member of the portable character set has a code value equal to its value when used as the lone character in an integer character constant.

読めば判るとおり、wchar_tの決まり事は

数値型であること wchar_t1文字でその文字集合の全ての文字を表せること nul文字は(wchar_t)0であること PCSの文字はwchar_t == charであること(つまり L'A' == 'A'であること)

これだけしか決まってません。

ふつーC言語で「未定義」といやー「実装依存」であるわけで、これ以外の挙動

例えばwchar_tの値を直に参照(例えば if (wc == 0x1234)とか)するとそれはすなわち

死亡フラグちゅーことです。

そもそもこの4.の条件があるので、EBCDICなどISO646と互換性の無い

文字コードを使用する 夜王 ホストなどの世界においては、wchar_t == UCS2/4を採用すると

たちまちwchar_t == charの仕様を満たせなくなりますやね(UCS2/4はISO646-US互換なので)。

つまりは元々wchar_tをUCS2/4のコードポイントとして実装すること自体無理があるわけで *1 。

しかーし一方でC99には事前定義マクロ__STDC_ISO_10646__というものがネジ込まれております。

__STDC_ISO_10646__ An integer constant of the form yyyymmL (for example, 199712L). If this symbol is defined, then every character in the "Unicode required set", when stored in an object of type wchar_t, has the same value as the short identifier of that character. The "Unicode required set" consists of all the characters that are defined by ISO/IEC 10646, along with all amendments and technical corrigenda, as of the specified year and month.

この事前定義マクロが定義されている場合は常に

wchar_t == ISO10646(=Unicode) codepoint

を保証するというとってもアレなシロモノです。

ちゅーわけでこのエントリは正確には

wchar_t != Unicode(UCS2/4) ※但し事前定義マクロ__STDC_ISO_10646__が定義されていない場合

ですな、まぁでもwchar_t == Unicodeを期待したコードは移植性が無いちゅうことには何ら変わりはないんだけど。

んで移植性のないコードを書いたのなら

#if !defined(__STDC_ISO_10646__) #error "U.C.S!! U.C.S!!" #endif

とでも書いといて「お前の姉ちゃん次世代CCSだな」でないプラットフォームでは

エラー出すようにするのがマナーでございます。

ユージュアリーフォースユニコード 非__STDC_ISO_10646__環境でも常にwchar_t == Unicodeを想定したコードを書いて Linux/Windowsでは動くがSolarisや*BSDでは確実にクラッシュし、あのOSは不安定だと 初心者に思わせるキラーアプリ。ports/pkgsrc developerは死ぬ

まぁ具体的にそれぞれのOSがwchar_tをどーゆー実装してるかはまた次回以降で。

話を戻してじゃぁ__STDC_ISO_10646__の場合、前述のEBCDICはどうすんのよ？

ちゅう疑問が沸いてきますがそこは技術力より政治力(笑)

4.の条件について DR#279ちゅーバグレポが上がってきた際、どーどーと改悪しとりやすね。

これTC 2を読むと上記の4.の条件は削除され以下のよなコメントが書かれておりやす。

C90 specifies the rule that L'x' == 'x' for any member x of the basic character set. The Committee discussed whether to relax or tighten this rule. In AMD1, this rule is preserved without any changes. Applying the rule to all single-byte characters, however, imposes an unnecessary constraint on implementations with regard to wide-character encodings. It prohibits an implementation from having a common wide-character encoding for multiple multibyte encodings. It also prohibits an implementation from having a wide-character encoding based on a different standard than its single byte encoding (e.g., ISO 10646 and EBCDIC).

これ困ったことにソース互換性がC90AMD1→C99で失われちまうのだけどね。

wchar_t wc = L'A'; int c = 'A'; if (wc == c) { ... }

みたいなコードを書いた場合、C90AMD1まではPCSの範囲ならこの条件分岐はOKだったのに

C99TC2以降はこのコードはnul文字以外では場合は未定義動作となってしまったという。

これコンパイラでも警告だせないような変更だし困るのですが…にんともかんとも。

(追記) DR#321の件を忘れてました、 ここ参照。

まぁさらっと見ただけでも__STDC_ISO_10646__って技術的に無理を通してるのが判りますが

問題点はこれだけにはとどまりません。

そのへんの話は既にitojunさんの paperで

「なぜUnicodeでは足りんのか？(Why Unicode is not enough?)」として語られていますので

今更私が書いても「余計なもの(-1)」になる気もしますが、これも次回以降にて説明したいと思います。