斜道倉庫

いろいろ遊んだことについて書いていく。

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でラップしておくと多分困らない。