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