syghの新フラグメント置き場

プログラミングTipsやコード断片の保管場所です。お絵描きもときどき載せます。

Visual C++とUTF-8マルチバイト

Visual C++ (MSVC) には

#pragma execution_character_set("utf-8")

というプラグマがあって、これを使うとコンパイル時にマルチバイト文字列リテラルプレフィックスなしの"XXX")をOSのANSIコードページ文字列リテラルShift_JIS:CP932とか)ではなくUTF-8文字列リテラルとして扱うようにすることができるんですが、Visual C++ 2012では使えなくなっているようですね。Visual C++ 2013では復活している模様。ちなみにMSVCではソースファイルのテキストエンコードコンパイル結果に直接関係ありませんが、ワイド文字列リテラル(L"XXX")やコメントの中に直接Unicode文字を埋め込む場合はUTF-8/UTF-16エンコードを使います。たとえ今すぐ国際化対応はしないとしても、Shift_JISその他のANSIエンコードはこの先使い続けていてもいいことは何ひとつないし害悪になるだけなので、さっさとドブに捨てましょう。

なお、ANSIエンコードのソースファイル中の文字列リテラルでどうしてもUnicode文字を表現したい場合、16進数表記の整数値を使います。MSVCのワイド文字・ワイド文字列はUTF-16ですが、他の処理系ではUTF-16とは限らないので注意が必要です。移植性の観点からはC++11のchar16_tを使うのがベストです。

_wsetlocale(LC_ALL, L"");
const wchar_t str[] = { 0x3042, 0x3044, 0x3046, 0x3048, 0x304A, 0x0000 }; // L"あいうえお"
wprintf(L"%ls\n", str);

それはそうとC++11のu8プレフィックスも早くサポートして欲しいです。つってもWindowsのネイティブエンコードUTF-16なのであまり使うことはないと思いますが……LuaやFBX SDKみたいにWindowsにおいても内部エンコードUTF-8ベースであるようなライブラリを使うときは利用価値があるかもしれません。

2019-09-26追記:
Visual C++ 2015ではu8プレフィックスが使えるようになっています。

const char str[] = u8"あ";
for (char c : str) {
    const unsigned u = static_cast<unsigned>(c) & 0xFFU;
    printf("%02X ", u);
}
printf("\n");
// → E3 81 82 00

なお、Visual C++ 2015 Update 2以降では、execution_character_setプラグマは再び廃止 (obsolete) になったようです。2015 Update 3では一応まだ使えます。代わりにコンパイルオプション/execution-charsetが推奨されています。