UTF-8は2度、3度死ぬ(その1)

この記事はブルータスお前もかの続きです。

きっかけは、ふっとしたところから

一晩たってMS932もUTF-8も、なぜか「ファイル構成」と出したつもりが、文字化けして、最初の字が「繝」になっている事に気づく。さて「繝」って何だろう?文字コードを調べてみる。

シフトJIS(0x8374) UTF-8(0xE38395)
シフトJIS(0xE383) UTF-8(0xE7B99D)

お気づきでしょう、「フ」のUTF-8の先頭2バイトをシフトJISで出すと、「繝」になるのです。そして「setlocale(LC_ALL, "")」は、今のコードページが何であれ、OSのコードページ(MS932)にセットさせるのです。また、setlocale()では、UTF-8ロケールに設定出来ません。
ここで疑問が、ではsetlocale()を取ってしまうと、何が起きるのだ?と。念のため、別の日本語行も追加しておきましょう。

>gcc main.c
>a
ファイル構成
abcファイル表示

おっ文字化けせずにUTF-8で出た〜。なんだよ、つまりはchcp 65001でコードページをUTF-8に変えても、setlocale()でMS932(≒シフトJIS)を持ってきてたのかよ〜orz。Windowsのsetlocale()意味不明!
再度msdnを読んでると、プログラム起動時に「setlocale(LC_ALL, "C")」を実施しているとのこと。つまり、すべての出来事はASCIIで処理される様です。非常に気持ちが悪いですが、ASCIIとUTF-8は干渉しないですし、結果的に、コードページをリロードしていないことから、UTF-8のWondows Cプログラムはsetlocale()しなければ良いのです。

重大な事忘れてた

そう、ここまですべてC言語でテストしてます。C++(g++)を実行したらどうなるのでしょう。まあ、出自が同一ですから、MS932のだめ文字は省略してUTF-8から行きましょう。
今回のサンプル(保存形式 UTF-8)

#include <iostream>

int
main()
{
    std::cout << "ファイル構成" << std::endl;
    std::cout << "abcファイル表示" << std::endl;

    return 0;
}


何でしょう?これ。2行目無いし。念のため、ファイルにリダイレクトして、内容を確認したところ、そちらでは問題ありませんでした。
さすがに・・・からは、情報は得られませんよ〜。仕方が無いので、ストリームI/Oの低レベルI/Fに変えてみましょう。

#include <iostream>

int
main()
{
    std::cout.write("ファイル構成\n", 19);
//    std::cout << "abcファイル表示" << std::endl;

    return 0;
}


(T-T)何かの呪いでしょうか?もちろん、リダイレクトしたファイルの中には、「ファイル構成」が格納されていました。
ええーい、貴様なんぞこうしてしまえ〜!!

//#include <iostream>
#include <cstdio>

int
main()
{
//    std::cout.write("ファイル構成\n", 19);
//    std::cout << "abcファイル表示" << std::endl;
    printf("ファイル構成\n");
    printf("abcファイル表示\n");

    return 0;
}


おっC++(g++)でも、UTF-8が文字化けせずに出ましたね(と言うか出させたね)。ストリームI/Oに、元凶が住んでいそうですが、流石にライブラリの中まで、調べる気が起きないので…

結論
C++(g++)でもprintf()を使おう。駄目だこりゃ