3

わかりました、私はこれを持っています:

AllocConsole();
SetConsoleOutputCP(CP_UTF8);
HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsoleA(consoleHandle, "aΕλληνικά\n", 10, NULL, NULL);
WriteConsoleW(consoleHandle, L"wΕλληνικά\n", 10, NULL, NULL);
printf("aΕλληνικά\n");
wprintf(L"wΕλληνικά\n");

さて、問題は、エンコーディング ファイルによっては、これらの作品の一部のみが保存されたということです。wprintf は機能しませんが、その理由は既にわかっています (狭い文字しか受け付けない Microsoft stdout の実装が壊れています)。それでも、私は他の3つに問題があります。ファイルを署名 (BOM) なしで UTF-8 として保存し、MS Visual C++ コンパイラを使用すると、最後の printf のみが機能します。ANSI バージョンを機能させたい場合は、文字数 (?) を 18 に増やす必要があります。

WriteConsoleA(consoleHandle, "aΕλληνικά\n", 18, NULL, NULL);

文字列は UTF-8 バイト シーケンスとして保存されるため、WriteConsoleW は機能しないと思いますUTF-8。

BOM を使用して UTF-8 で保存すると (当然のことですが)、WriteConsoleW が何らかの形で機能し始め (???)、他のすべてが停止します (文字の代わりに ? が表示されます)。同じフォーマットを維持するには、WriteConsoleA の文字数を 10 に減らす必要があります (そうしないと、8 つの追加の四角形が得られます)。基本的に、WTF?

では、UTF-16 (Unicode - コードページ 1200) に行きましょう。WriteConsoleW のみで動作します。フォーマットを正確に保つには、WriteConsoleA の文字数を 10 にする必要があります。

UTF-16 ビッグ エンディアン モード (Unicode - コードページ 1201) で保存しても、何も変わりません。繰り返しますが、何ですか?ファイルに保存するときに、文字列内のバイト順を逆にするべきではありませんか?

結論として、文字列をバイナリ形式にコンパイルする方法は、使用するエンコーディングによって異なります。したがって、文字列を格納するためのポータブルでコンパイラに依存しない方法は何ですか? コンパイル前にある文字列表現を別の文字列表現に変換するプリプロセッサがあるので、ファイルを UTF-8 で保存し、UTF-16 で必要な文字列のみをマクロでラップして前処理することができます。

4

2 に答える 2

0

私が知る限り、間違っているか100%正しくない仮定が少なくともいくつかあると思います。

問題は、エンコーディング ファイルによっては、これらの作品の一部のみが保存されていたことです。

もちろん、エンコーディングは文字列リテラルの解釈方法を決定するためです。

wprintf は機能しませんが、その理由は既にわかっています (狭い文字しか受け付けない Microsoft stdout の実装が壊れています)。

私はそのことを聞いたことがありませんが、これはプログラムに設定されたロケールに依存していると確信しています。ロケールが設定されていて、出力がドイツ語のウムラウトなどを使用しても問題ない作業プロジェクトがいくつかあります。

ファイルを署名 (BOM) なしで UTF-8 として保存し、MS Visual C++ コンパイラを使用すると、最後の printf のみが機能します。ANSI バージョンを機能させたい場合は、文字数 (?) を 18 に増やす必要があります。

これは、ANSI バージョンでは ANSI 文字列が必要であるのに対し、UTF-8 でエンコードされた文字列 (ファイルのエンコーディングに基づく) を渡しているためです。コンソールが UTF-8 変換を処理するため、出力は引き続き機能します。ここでは、基本的に未加工の UTF-8 を出力しています。

文字列は UTF-8 バイト シーケンスとして保存されるため、WriteConsoleW は機能しないと思いますUTF-8。

私はそうは思いません(なぜそれが機能しないのかはわかりませんが)。見つけやすい文字列を設定して、結果のバイナリでそれを探してみましたか? 確かに UTF-16 でエンコードされていると思います。BOM が欠落しているため、コンパイラは全体を狭い文字列として解釈し、UTF-8 のものを間違って変換する可能性があると思います。

BOM を使用して UTF-8 で保存すると (当然のことですが)、WriteConsoleW が何らかの形で機能し始め (???)、他のすべてが停止します (文字の代わりに ? が表示されます)。同じフォーマットを維持するには、WriteConsoleA の文字数を 10 に減らす必要があります (そうしないと、8 つの追加の四角形が得られます)。基本的に、WTF?

これはまさに私が上で説明したことです。これで、ファイルが ANSI (または何らかのコードページ) ではなく UTF-8 であることをコンパイラが認識するようになったため、ワイド文字列が適切にエンコードされます。ナロー文字列も、使用されているロケールに適切に変換されます。


全体として、事前に適切なコードページや UTF コードを使用してすべてをエスケープしない限り、エンコーディングに依存しない方法はありません。現在のすべてのコンパイラがファイルを適切に読み取って解釈できると思うので、BOM 付きの UTF-8 に固執するだけです (Microsoft のリソース コンパイラを除く; UTF-8 で 2012 バージョンをフィードしようとはしていませんが)。

編集:

類推を使用するには:

基本的に生の画像をファイルに保存していて、他のプログラムがグレースケール、パレット化、またはフルカラーの画像として読み取ろうとしても、正しく動作することを期待しています。これは機能しません (違いが小さいにもかかわらず)。

于 2013-04-06T09:55:23.333 に答える
0

答えはここにあります。

引用:

コンパイラが UTF-8 と UTF-16 の文字列をコンパイル済み出力に混在させることはできません! したがって、1 つのソース コード ファイルを決定する必要があります。

  • BOM で UTF-8 を使用し、UTF-16 文字列のみを生成します (つまり、常に L プレフィックスを使用します)。
  • または BOM なしの UTF-8 であり、UTF-8 文字列のみを生成します (つまり、L プレフィックスを使用しないでください)。
  • 7 ビットの ASCII 文字は関係なく、L プレフィックスの有無にかかわらず使用できます

移植可能でコンパイラに依存しない唯一の方法は、ASCII 文字セットとエスケープ シーケンスを使用することです。これは、コンパイラが UTF-8 でエンコードされたファイルを受け入れるという保証がなく、これらのマルチバイト シーケンスのコンパイラの処理が異なる可能性があるためです。

于 2013-04-09T09:52:02.797 に答える