読者です 読者をやめる 読者になる 読者になる

C/C++での日本語文字列の扱い、どうすればよいか


このエントリーをはてなブックマークに追加

C/C++でどう日本語の文字列を扱えばよいのか、いまだによく分かっていない。頭を整理するために、自分が理解している範囲のことを一度まとめてみる。嘘を書いているかもしれない。また、環境はWindowsのみを想定している。

マルチバイト文字列とワイド文字列

文字列には大きくわけてマルチバイト文字列とワイド文字列の二種類ある。

マルチバイト文字列

まずマルチバイト文字列。マルチバイト文字列は以下のように宣言する。

char strmb[] = "こんにちは”;

どの文字コードが使われるかは実行環境によって異なるっぽい(自信なし)。Windows + Visual Studioの場合は多分CP932(Shift_JISの亜種(?))。char strmb[] = "こんにちは hello”という風に英数字を混ぜてもよい。ただ日本語以外の言語を混在させることはできない。

ワイド文字列

次にワイド文字列。ワイド文字列ではASCIIも含めたすべての文字を原則2バイトで表現する。ワイド文字列を使う前には、現在のロケールを設定する必要がある。

ここでロケールの設定について詳しく書く。ロケールを設定するには、setlocale( LC_ALL, "japanese" )という風にsetlocale()関数を使う。
ここで第二引数を""と言う風に空文字列にすると、OSから取得されたロケール自動的に設定される(参考)。現在のロケールを確認するには、setlocake (LC_ALL, NULL ); という風に、第二引数をNULLにする。自分がVS2013で試したところ、プログラム起動時のロケールは"C"で、setlocale (LC_ALL, "" )した後のロケールは "Japanese_Japan.932"だった。ここで、Japaneseは日本語、Japanは国/地域、932はコードページである。

ロケールを設定した後、ワイド文字列は以下のように宣言する。

wchar_t strw[]  = L"さようなら";

Lを書かないとダメ。

比較表

マルチバイト文字列とワイド文字列とを比較すると以下のようになる。

マルチバイト文字列 ワイド文字列
日本語文字列の表し方 英字を1バイト、日本語文字を2バイトで表現 英字、日本語文字、その他を原則2バイトで表現
宣言例 char strmb[] = "こんにちは" setlocale( LC_ALL, "" ); wchar_t strw[] = L"さようなら";
STLの文字列 std::string std::wstring
プリント printf("%s\n", strmb); wprintf(L"%s\n", strw);

TCHARについて

WindowsプログラミングではTCHARというのがやたら出てくる。TCHARは、Visual Studioのプロジェクトのプロパティの一項目「文字セット」で「Unicode 文字セットを使用する」を選んだ時にはwchar_t、「マルチ バイト文字セットを使用する」のときにはcharにtypedefされる。

Win32 APIをバリバリ使って開発する場合は、TCHARに対応する関数がたくさん用意されているのでTCHARを使って問題を感じることは少ない。しかし外部ライブラリ(OpenCVなど)を使う場合は、マルチバイト文字列かワイド文字列かのどちらかしか使えない場合が多い。その場合、TCHARを、その外部ライブラリが受け付ける文字列に変換する必要があるが、そのとき「文字セット」が何に設定されているかによって変換処理を切り替えなければいけなくなる。TCHARを使うことで、返って手間が増えているような気がする。

TCHARは、Windowsべったりなコードを書く場合しか使わないほうがよいのではないか、というのが今の個人的な結論である。

マルチバイト文字列とワイド文字列ではどちらを使うべきか

ではマルチバイト文字列とワイド文字列ではどちらを使うべきか。これもよくわからん。自分しか使わないような書き捨てのコードならマルチバイト文字列でよさそうな気もするが、これからコードを資産として保持していくことを考えるならワイド文字列を使うほうがよいのだろうか。

まだよくわかってないこと

  • .cファイル自体の文字コードはどうすればよいのか?
  • .cファイルの文字コードと、printf()などで出力される文字コードの関係は?
    • いまいちこの辺についてはっきり言及しているサイトが見つからない。
  • setlocale()で932以外のコードページって設定できないの? 65001(UTF-8 BOM有)を設定しようとしてもできなかった

参考