すっかり間が空いてしまいました、すみません。

さて前回(1)では簡単に済ませましたが、本来標準Cライブラリに対するマルチバイト・ワイド文字切替の対応は、本来Windows APIのものと別個に行われています。そのこともあって少々厄介です。

まず、<tchar.h>ではUNICODEが定義されているかどうかは関係ありません。_UNICODEが定義されているかどうかを見ています。ほかにも関係するものが同様に<windows.h>以下とは別に用意されています。

<windows.h> <tchar.h>
UNICODE _UNICODE
TCHAR _TCHAR
TEXT及び__TEXT _T及び_TEXT

更に_MBCSが定義されているかどうかという第3の状態が存在します。これが定義されていればマルチバイト文字、そうでなければシングルバイト文字を使用するということになります。

次のプログラムではその違いが現れます。_tcschrはstrchr/_mbschr/wcschrの3種類に展開されます。

//test.cpp
//VC++ 8 cl /EHsc test.cpp
#include <stdio.h>
#include <string.h>
 
#include <tchar.h>
 
int main(void)
{
  const _TCHAR* p = _tcschr(_T("ア"), _T('A'));
  if (p != 0)
    _tprintf(_T("p == '%c'\n"), *p);
  else
    _tprintf(_T("not found\n"));
 
  return 0;
}

このままコンパイルして実行すると、p == ‘A’という出力になります。Shift_JISで「ア」の2バイト目はちょうど「A」の文字コードの値と一致するからです。

しかし#define _MBCSを書くと一転、not foundという出力になります。「ア」であるの一部分であるため先程とは違って「A」の位置を結果として返しません。

ちなみに_tprintfはprintf/wprintfの2種類へ展開されます。_MBCS時にもprintfが選択されます。このように区別の必要の無い場合、マルチバイト文字版とシングルバイト文字版は共通したものになります。


なぜ同じもこのように同じものが2つあるかというと、おそらくはWindows APIという1ライブラリと標準ライブラリの独自拡張という違いが現れたということなのでしょう。

CとC++では、どちらもその標準規格である種の識別子(名前)を処理系のために予約しています。予約された識別子は処理系(コンパイラ・標準ライブラリなど)以外が使ってはいけません。逆に処理系が予約されていない識別子を使うこともいけません。そのため似たようなものが2つも存在することになったのではないかと思います。

なお処理系のために予約された名前とは下線から始まるものだと思っておけば大体問題ありません。

細かく話すと、次のようになります。C++の場合ですが、Cでも大体同じです。まず、下線に続き英大文字、または下線2つで始まる名前は、常に処理系のために予約されています。また、下線で始まる名前は大域名前空間において処理系のために予約されています。なお、この隙をついたのがBoost.Bindの_1や_2といった名前です;-)。


ところで、Cの標準規格では全ての関数に対してワイド文字版があるわけではなく、マルチバイト版は影もありません。これら標準規格に存在しないものは全てVisual C++が標準Cライブラリに対する独自拡張という扱いで用意しています。上の_mbschrもそうですし、ワイド文字関数では例えばfopenに対する_wfopenがそうです。独自拡張の関数は全て下線で始っています。そういうことを気にするときには使わないでくださいということです。


スポンサード リンク

この記事のカテゴリ