[ C++で開発 ] [ Visual C++雑多メモ ]
Visual C++は、ワイド文字(Unicode)/マルチバイト文字のプログラムコードを、デファイン_UNICODEおよびUNICODEの制御だけで切り替えられるようにする仕掛け(本記事ではTCHARと呼称)を用意しています。Windows のAPIやVisual C++の標準ライブラリはほとんどがこのTCHARの仕掛けを使っています。
ところが、アプリケーションコードでTCHARの仕掛けを使う場合に、どのようにプログラミングすればよいか、情報がまとまっていません。そこで、自分でプログラミングをしていて引っかかったり調べたことなどを雑多メモとして残すことにしました。
TCHARを使うと、標準C++プログラミングとは相性が悪いです。Visual C++というのはC++言語の亜種で、Windowsアプリケーション開発用言語として認識しておくのが吉。
TCHARの仕掛けを使う場合、コンパイルオプションでデファイン_UNICODEによりワイド文字かマルチバイト文字かを切り替えます。
次に、文字や文字列を扱う型は、直接char やwchar_tを使わず、tchar.h で定義される型_TCHARなどを使います。
文字リテラル、文字列リテラルは、_TEXT(...)または_T(...)を使います。
ライブラリ関数は、マルチバイト文字決め打ちのものは使わず、tchar.h で定義されるラッパー(typedef)を使用します。
TCHARコーディング | マルチバイト文字決め打ちコーディング | ワイド文字決め打ちコーディング |
---|---|---|
#include <locale.h> : setlocale(LC_ALL, "Japanese_Japan.932"); |
不要 |
#include <locale.h> : setlocale(LC_ALL, "Japanese_Japan.932"); |
#include <tchar.h> : _TCHAR* text = _T("こんにちは"); _TCHAR ch = _T('窓'); |
char* text = "こんにちは"; |
wchar_t* text = L"こんにちは"; |
_printf(text); |
printf(text); |
wprintf(text); |
#if defined(_UNICODE) || defined(UNICODE) # define tcout std::wcout #else # define tcout std::cout #endif #include <iostream> : tcout << _T("こんにちは") << std::endl; |
#include <iostream> : std::cout << "こんにちは" << std::endl; |
#include <iostream> : std::wcout << L"こんにちは" << std::endl; |
#include <string> typedef std::basic_string<_TCHAR> tstring; : tstring message = _T("こんにちは"); |
#include <string> : std::string message = "こんにちは"; |
#include <string> : std::wstring message = L"こんにちは"; |
TCHARプログラミングをする場合、C++標準ライブラリのストリームをラップする方法が提供されていません。
回避策として、デファインに応じて coutかwcoutかを置き換えるマクロを定義して利用します。
#if defined(UNICODE) || defined(_UNICODE) # define tout std::wcout # define tin std::wcin # define terr std::wcerr # define tlog std::wclog #else # define tout std::cout # define tin std::cin # define terr std::cerr # define tlog std::clog #endif
アンダースコアを先頭に付ける命名は、コンパイラ(処理系)に予約されているので付けませんでした。
また、ネームスペースstdも予約されているので、stdは付けていません。
今回、std::clog(std::wclog)の存在を初めて知りました。バッファリングされる標準エラー出力です。
TCHARプログラミングをする場合、C++標準ライブラリの文字列をラップする方法が提供されていません。
回避策として、_TCHAR型をテンプレートの引数とする型を定義します。
typedef std::basic_string<_TCHAR> tstring
stringstreamも同様に定義するとよいかもしれません。
typedef std::basic_stringstream<_TCHAR> tstringstream; typedef std::basic_ostringstream<_TCHAR> tostringstream; typedef std::basic_istringstream<_TCHAR> tistringstream;