TCHARでいこう。

最近のVisualStudio(VisualC++ 2008)では、プロジェクトのデフォルトがUNICODEになっている。UNICODEと言ってもutf-8ではなくて、UTF-16LEのことだと捉えてください。きょうび、VisualStudioでC++を触ることがこの先、何度あるかわかんないけれども、メモを残しておきます。

charはもう古い。TCHARで行こうぜ。

昔の話では、NT系はUNICODE対応、95系は非対応、とかで、使い分けが存在していた。
TCHAR という char の代わりみたいなものがあって、こう定義されていた。

#ifdef UNICODE
    typedef WCHAR TCHAR;
#else
    typedef char TCHAR;
#endif

コンパイラ(cl)で /D UNICODE がつくかつかないかで、charか、wcharか、切り替わるような仕組みになっている。


NT系ということは、WindowsVistaとか、Windows7とかのことで、もうNT系じゃないWindowsを捜すほうが難しい、という現代の現実を受け止めると、選択肢は実は一つであることがわかってくる。もう全部wcharで書いてしまおうぜ。というのも手かもしれないが、wcharも哀しいかな、UNICODEの定義で実は変わってしまう。

#ifdef UNICODE
    typedef wchar_t WCHAR;
#else
    typedef short WCHAR;
#endif
↑これは正しくない表記。追記参照

9/11追記:
この説明は誤り。コメントで指摘いただいた。こちらを見るとwchar_tをネイティブ型とするか、unsigned shortになるか変化するらしい。
http://msdn.microsoft.com/ja-jp/library/dh8che7s.aspx

というわけで、大人しくTCHARの使い方を覚えたほうがまぁ、今のところ現実的かな、という気がします。

文字列操作関数

msdnを見れば、大抵の関数は、TCHARを使う場合はこの関数で行け、と書いてある。この辺を知っていたら、まずはなんとかなると思う。

普通の関数 TCHARで使用可 説明
memset memset サイズは文字数で指定
strlen _tcslen 長さを文字数で取得
strncpy _tcsncpy_s 文字列をコピー
strcmp _tcscmp 文字列比較
sprintf _stprintf_s 書式付き文字列作成

自然と _s がつく関数を使うことになるのでバッファオーバーフローとか起きにくくなると思う。

_Tマクロ

char型のように文字列は宣言できず、_T()マクロを使う。

char * a = "abcd";      // こうではなく
TCHR * a = _T("abcd");  // こう書きましょう

いたるところに、_T() が付きます。最初は見づらいと思いましたが、慣れの問題です。

ファイルIOの注意

UNICODE がつくと、utf-16LE 相当になるようです。LEというのはリトルエンディアンというやつで、テキストファイルを書きこむ時に、最初にこのファイルはリトルエンディアンで読んでね、という意味のBOM(Byte Order Mark)を自分で書く必要があります。

// 既にファイルはCreateFileなどでオープン済みとする
BYTE BOMLE[2];
BOMLE[0] = 0xFF;
BOMLE[1] = 0xFE;
DWORD writesize = 0;
WriteFile(hFile, BOMLE, 2, &writesize, NULL);

書き始めにこういう処理があったほうが親切です。というか、メモ帳で見れるファイルにしたければ必須です。

可変長引数

TCHAR環境で使う方法にしばらく悩みました。最終的にこういう感じに落ち着きました。

include <stdargs.h>
void my_putf(TCHAR *format, ...)
{
va_list args;
TCHAR buf[1024];
ZeroMemory(buf, 1024);

va_start(args, format);
_vstprintf_s(buf, 1024, format, args);
va_end(args);
// あとはいろいろ
}

1024文字を超える場合は、こういう手抜きをせずに、必要サイズをmallocで取ってfreeするべきです。MSDNのサンプルはそうなっています。が、TCHARで書かれていないのが惜しい。
http://msdn.microsoft.com/ja-jp/library/xa1a1a6z%28v=vs.80%29.aspx