山本さんの仕事は速いです。前回のミーティングでUnicode対応が欲しいという話をしたところ、導入されることになりました。しかも私はStringさえUnicodeであればというつもりでいましたが、なんと全体的に行うことになり、早速コンパイラオプションによってCharが1バイトになったり2バイトになったりする機能がもう実装されてしまいました。つまりこれからのCharはC/C++でのTCHAR/_TCHARのような存在です。従来の符号付1バイト整数型という立場は新しくSByte型を導入してその座を譲っています。
これからWindows APIの宣言を両対応にしますが、その前に頭の整理を兼ねてC/C++上でのWindows APIにおけるUnicode対応のプログラムを書く方法をここにまとめておきたいと思います。
C/C++におけるWindows APIプログラミングでは、マルチバイト文字型としてCHAR、ワイド文字型としてWCHARを定義しており、それぞれcharとwchar_tのtypedefとなっています。
文字を扱う関数はMessageBoxAとMessageBoxW のように2種類用意されています。MessageBoxという名前は、プリプロセッサで識別子UNICODEが定義されている(#defineされている)かどうかでそのどちらかとなります。
同じように文字を扱う型としてUNICODEの定義の有無によってCHAR/WCHARに切り替えられるTCHARがあります。これに関連する型としてLPTSTR (TCHAR*)、LPCTSTR (const TCHAR*)などがあります。
さらに、C/C++ではマルチバイト文字列を”String”、ワイド文字列をL”String”のように書きます。そこで、その差を吸収するマクロとしてTEXTが定義されています。結局MessageBoxをワイド文字対応させて書くと次のようになります。
1 2 | PCTSTR msg = TEXT("Hello, world"); MessageBox(0, msg, TEXT(""), MB_OK); |
さて、C/C++にはもちろん標準ライブラリがありますが、これもそれぞれ同様の対処がなされています。まずはC++のほうからです。これはテンプレートが使われているためとても簡単で、単にTCHARをテンプレート引数に渡せば大抵事足ります。
たとえば、std::stringはstd::basic_string<char>のtypedefです。つまりstd::basi_string<TCHAR>とすればUNICODEによる切替に対応した文字列を扱えます。typedef std::basic_string<TCHAR> tstring;と自分でtypedefしておけば便利でしょう。
同様にファイルの読み書きもstd::basic_[io]fstream<TCHAR>とすれば良いのです。ただし、コンストラクタ及びメンバ関数openではファイル名の引数の型が規格上常にconst char*ですが、少なくともVisual C++では独自拡張としてconst wchar_t*を取るものを多重定義しているので、移植性を気にしなければ問題ありません。
標準入出力はGUIプログラムでは使う機会がないでしょうから、ここでは省略します。
さて次に標準Cライブラリです。こちらは使うだけなら<tchar.h>をインクルードすれば様々な関数がワイド文字・マルチバイト文字の切替に対応させたマクロがあります。たとえばstrlen/wcslenに対して_tcslen、fopen/_wfopenに対して_tfopenという具合です。
これだけ知っていれば通常困ることはないでしょう。ここで一旦終わります。続きはまた明日。
スポンサード リンク |