Windowsのコンソールで直接UTF-8での入出力をするとバグる
概要
Windowsのコンソールを dhcp 65001 で一応UTF-8を表示させる。
C/C++のアプリケーションの標準入出力を使ってコンソールからインタラクティブな動作をさせたとき、日本語を入れるとバグる。
なので、ユーザー入出力部分はshift-jisにしておくのが良い。
詳細
Windowsのコンソールにはコマンドプロンプトとパワーシェルがある。
それぞれ dhcp 65001 コマンドで一応UTF-8環境にできる。
しかしパワーシェルではフォントが変えられないので表示できない。すべて、□や☆や?マークになってしまう。
コマンドプロンプトではフォントを変えれば表示できる。しかし、アプリケーションの入力に使えないことがあるようだ。
以下のコードは、入力テキストをそのまま返す機能+入力をバイトごと分けて値を表示する機能のアプリケーションのc++コードである。
input1()はC++の標準入出力で行単位で、input2()はCの標準入出力で行単位で、input3()はCの標準入出力でバイト単位で読み書きを行っている。
#include <iostream> #include <stdio.h> #include <string> void input1() { std::string s; std::cin >> s; std::cout << s<< std::endl; for (unsigned char c : s) { std::cout << int(c) << " "; } } void input2() { std::string s; char m[2048] = { 0 }; fgets(m, 2048, stdin); puts(m); s = m; for (unsigned char c : s) { printf("%d ", c, stdout); } } void input3() { std::string s; char m[2048] = { 0 }; char c; int i = 0; while ((c = getc(stdin)) != EOF) { m[i] = c; ++i; } puts(m); s = m; for (unsigned char c : s) { printf("%d ", c, stdout); } } int main() { std::string s; // input1(); // input2(); input3(); }
上記のコードを関数1つだけ実行されるよう修正してからコンパイルして、関数それぞれがどのように振舞うのか実験する。
結果が以下のとうりである。
input1()
>ConsoleApplication1.exe hogeほげhoge hogehoge 104 111 103 101 0 0 104 111 103 101 >echo hogeほげhoge|ConsoleApplication1.exe hogeほげhoge 104 111 103 101 227 129 187 227 129 146 104 111 103 101
input2()
>ConsoleApplication1.exe hogeほげhoge hoge 104 111 103 101 >echo hogeほげhoge|ConsoleApplication1.exe hogeほげhoge 104 111 103 101 227 129 187 227 129 146 104 111 103 101 10
input3()
>ConsoleApplication1.exe hogeほげhoge hoge 104 111 103 101 ^C >echo hogeほげhoge|ConsoleApplication1.exe hogeほげhoge 104 111 103 101 227 129 187 227 129 146 104 111 103 101 10
以上の結果から、アプリケーションからのパイプ入力であれば正しく動作する。
しかし、コンソールから入力するとアプリケーションはなぜか1ビットの0を受けとる。
したがって、ユーザー操作で動作させるコンソールアプリケーションは少なくとも入出力部分はUTF-8で作らない方がよい。内部でUTF-8を使う場合でも入出力はshift-jisでラップしておくと多分困らない。