1) 正しい値が wchar_t に入っていることを確認します。ワイド文字列リテラルを生成するコンパイラはL"ä"
、ソース コード エンコーディングからワイド実行文字セットに変換する必要があります。
2) プログラムのロケールが正しいことを確認します。これを行うことができますprintf("%s\n", setlocale(LC_ALL, NULL));
問題は 1) だと思います。なぜなら、プログラムのロケールが正しく設定されていなくても、期待どおりの出力が得られるからです。ソース コードのエンコーディングの問題を回避するために、 のような非 ASCII 文字をエスケープできますL"\x00E4"
。
1 #include <iostream>
2 #include <clocale>
3
4 int main () {
5 std::printf("%s\n", std::setlocale(LC_ALL, NULL)); // prints "C"
6
7 char a[10];
8 wchar_t w[10] = L"\x00E4"; // German a Umlaut
9 std::printf("0x%04x\n", (unsigned)w[0]); // prints "0x00e4"
10
11 std::setlocale(LC_ALL, "");
12 printf("%s\n", std::setlocale(LC_ALL, NULL)); // print something that indicates the encoding is ISO 8859-1
13 int e = std::wcstombs(a, w, 10);
14 std::printf("%i 0x%02x\n", e, (unsigned char)a[0]); // print "1 0xe4"
15 }
16
C および C++ プログラムの文字セット
ソース コードでは、「基本ソース文字セット」のスーパーセットである「ソース文字セット」の任意の文字を使用できます。コンパイラは、文字列および文字リテラル内の文字をソース文字セットから実行文字セット (またはワイド文字列および文字リテラルの場合はワイド実行文字セット) に変換します。
問題は、ソース文字セットが実装依存であることです。通常、コンパイラは、ソース コードに使用するエンコーディングを認識するだけでよく、そのエンコーディングの任意の文字を受け入れます。GCC にはソース エンコーディングを設定するためのコマンド ライン引数があり、Visual Studio は、UTF-8 または UTF-16 のいわゆる Unicode 署名のいずれかを検出しない限り、ソースがユーザーのコードページにあると想定し、Clang は現在常に UTF- 8.
コンパイラがコードに適切なソース文字セットを使用すると、「実行文字セット」で文字列と文字リテラルが生成されます。実行文字セットは、基本的なソース文字セットのもう 1 つのスーパーセットであり、実装に依存します。GCC はコマンド ライン引数を使用して実行文字セットを設定し、VS はユーザーのロケールを使用し、Clang は UTF-8 を使用します。
ソース文字セットは実装に依存するため、基本セット以外の文字を書き込むポータブルな方法は、16 進エンコーディングを使用して実行で使用する数値を直接指定するか、(C89/90 を使用していない場合)実行文字セット (ワイド文字列および文字リテラルで使用される場合はワイド実行文字セット) に変換される汎用文字名 (UCN) を使用します。UCN は \uNNNN または \UNNNNNNNNN のように見え、コード ポイント値 NNNN または NNNNNNNN で Unicode 文字セットから文字を指定します。(C99 および C++11 では、サロゲート コード ポイントの使用が禁止されていることに注意してください。BMP 外の文字が必要な場合は、\U を使用して文字の値を直接記述します。)
ソース文字セットと実行文字セットはコンパイル時に決定され、プログラムを実行しているシステムのロケールに基づいて変更されることはありません。つまり、プログラムのロケールは、必ずしも実行文字セットに一致しない別のエンコーディングを使用します。ただし、ワイド実行文字セットは、サポートされているロケールで使用されるワイド文字エンコーディングに対応している必要があります。
Solaris Studio の動作
Oracle の Solaris 用コンパイラの動作は非常に単純です。ナロー文字列および文字リテラルの場合、特定のソース エンコーディングは指定されません。ソース コードからのバイトが実行リテラルとして直接使用されます。これは事実上、実行文字セットがソース ファイルのエンコーディングと同じであることを意味します。ワイド文字リテラルの場合、ソース バイトはシステム ロケールを使用して変換されます。つまり、正しいワイド リテラルを取得するには、ロケール エンコーディングを使用してソース ファイルを保存する必要があります。
ソース コードがロケールで指定されたものとは異なるエンコーディングで保存されていると思われるため、コンパイラは から正しいワイド文字列リテラルを生成できませんでしたL"ä"
。エディターが UTF-8 を使用している可能性があります。以下のプログラムで確認できます。
1 #include <iostream>
2 #include <clocale>
3
4 int main () {
5 wchar_t w[10] = L"ä"; // German a Umlaut
6 std::printf("0x%04x 0x%04x\n", (unsigned)w[0], (unsigned)w[1]);
7 }
8
wcstombs はワイド文字 0x00E4 を「ä」のラテン 1 エンコーディングに正しく変換できるため、上記を表示したいとします0x00E4 0x0000
。ソース コードのエンコーディングが UTF-8 の場合は、 が表示されます0x00C3 0x00A4
。