7

-finput-charset コンパイラ オプションを使用して g++ で UTF-16BE C++ ソース ファイルをコンパイルしようとしていますが、常に多くのエラーが発生します。詳細は次のとおりです。

私の環境(CentOS Linux):

  • g++: 4.1.2
  • アイコンv: 2.5
  • Linux 言語 (ターミナル): LANG="en_US.UTF-8"

サンプル ソース ファイル (UTF-16BE エンコーディングで保存):

// main.cpp:

#include <iostream>

int main()
{
    std::cout << "Hello, UTF-16" << std::endl;
    return 0;
}

私の手順:

  • -finput-charset オプションについて g++ のマニュアルを読みました。 g++ のマニュアルには次のように書かれています。

-finput-charset=charset 入力ファイルの文字セットから GCC が使用するソース文字セットへの変換に使用される入力文字セットを設定します。ロケールが指定されていない場合、または GCC がロケールからこの情報を取得できない場合、デフォルトは UTF-8です。これは、ロケールまたはこのコマンド ライン オプションでオーバーライドできます。現在、競合がある場合は、コマンド ライン オプションが優先されます。charset は、システムの「iconv」ライブラリ ルーチンでサポートされている任意のエンコーディングにすることができます。

  • したがって、次のようにコマンドを入力しました。

g++ -finput-charset=UTF-16BE main.cpp

これらのエラーが発生しました:

main.cpp:1 からインクルードされたファイル:

/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/iostream:1: エラー: プログラムで '\342' が外れています

/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/iostream:1: エラー: プログラムで '\274' が外れています

...(繰り返し、たくさん、約 4000+)...

/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/iostream:1: エラー: プログラムで '\257' が外れています

main.cpp: 関数 'int main()' 内:

main.cpp:5: エラー: 'cout' は 'std' のメンバーではありません

main.cpp:5: エラー: 'endl' は 'std' のメンバーではありません</p>

  • マニュアルのテキストは、文字セットが「iconv」ルーチンでサポートされている任意のエンコーディングである可能性があることを示唆しているため、コンパイル エラーは私の iconv ライブラリが原因である可能性があると推測しました。次に、iconv をテストしました。

iconv --from-code=UTF-16BE --to-code=UTF-8 --output=main_utf8.cpp main.cpp

「main_utf8.cpp」ファイルが期待どおりに生成されます。私はそれをコンパイルしようとしました:

g++ -finput-charset=UTF-8 main_utf8.cpp

入力文字セットを明示的に指定して何か問題があったかどうかを確認しましたが、今回は "a.out" がエラーなしで生成されたことに注意してください。実行すると、正しい出力が生成されました。

ついに...

どこを間違えたのかわかりませんでした。このコンパイラ オプションの例をいくつか見つけようとして Web を検索しましたが、見つかりませんでした。

お知らせ下さい!ありがとう!

さらなる編集:

みんなありがとう!あなたの返事は速いです!いくつかの更新:

  1. 「UTF-16」と言ったとき、「UTF-16 + BOM」を意味しました。実際、私は UTF-16BE を使用しました。上記のテキストを更新しました。
  2. UTF-16 以外のヘッダー ファイルが原因でエラーが発生したという回答もあります。これが事実である場合の私の考えは次のとおりです。C/C++ プロジェクトを作成するときは、常にいくつかの標準ヘッダー ファイルを含めますよね? stdio.h や iostream など。G++ コンパイラが、私たちが作成したソース ファイルのエンコーディングのみを処理し、標準ライブラリのソース ファイルを処理しない場合、この -finput-charset オプションは何のために存在するのでしょうか??

最終編集:

最後に、私の解決策は次のとおりです。

  1. 最初に、「Mr Lister」が以下に述べたように、ソース ファイルのエンコーディングを GB2312 に変更しました。これはしばらくの間うまくいきましたが、システムの他の部分のほとんどが通信とインターフェイスにまだ UTF-8 を使用しているため、後で自分の状況には適していないことがわかりました。そのため、多くの場所でエンコーディングを変換する必要があります...私の作業のオーバーヘッドであり、プログラムのパフォーマンスが低下する可能性もあります。
  2. 後で、すべてのソース ファイルを UTF-8 + BOM に変換しようとしました。このように、Windows の Visual Studio は問題なくコンパイルできますが、Linux の GCC は文句を言います。次に、BOM を削除するシェル スクリプトを作成し、GCC でコードをコンパイルする前に、まずこのスクリプトを実行します。
  3. 幸いなことに、プロジェクトで継続的インテグレーション ツールの TeamCity を使用してビルドを自動的に生成するため、Linux でコードを手動でビルドする必要はありません。毎日のビルドが始まる前にこのスクリプトを実行できるように、TeamCity のビルド手順を変更できます。
  4. この UTF-8 + BOM + スクリプト方式では、Linux でソース コードを編集しないことにしました。編集したい場合は、コードをコミットする前に、コードが正常にビルドできることを確認する必要があるためです。コードをビルドする前に BOM を削除するスクリプト。つまり、SVN はすべてのファイルが変更された (BOM が削除された) ことを報告するため、間違ったファイルを誤ってコミットするのが非常に簡単になります。この問題を解決するために、別のシェル スクリプトを作成して、BOM をソース ファイルに追加し直しました。私はまだ Linux で自分のコードを頻繁に編集するわけではありませんが、本当に必要なときは、コミット ダイアログで非常に長い変更リストに直面する必要はありません。
4

4 に答える 4

5

ブルースのエンコーディング

ソース コード ファイルに UTF-16 を使用することはできません。含めているヘッダーが<iostream>UTF-16 でエンコードされていないためです。ファイルが逐語的に含まれているよう#includeに、これは、無効なデータの大きなチャンク (明らかに約 4k) を含む UTF-16 でエンコードされたファイルが突然存在することを意味します。

何かに UTF-16 を使用する正当な理由はほとんどないため、これも同様です。

編集:エンコーディングサポートの問題について:OS自体はエンコーディングサポートを提供する責任がありません。これは、使用されるコンパイラに帰着します。

Windows 上の g++ は、Linux 上の g++ と同じエンコーディングを完全にすべてサポートします。これは、Windows で使用している g++ のバージョンが深く壊れた iconv ライブラリに依存している場合を除き、同じプログラムであるためです。

ツールチェーンを調べて、すべてのツールが正常に機能していることを確認してください。

代替として; ソース ファイルでは中国語を使用せず、実行中の実行可能ファイルでこれらを置き換えるために、英語のリテラルまたは単純なTOKEN_STYLE_PLACEHOLDERs を使用l10nして英語で記述します。i18n

Threedit: -finput-charsetほぼ間違いなく、コードページやその他のナンセンスの時代からの名残です。でも; ISO-8859-n ファイルはほとんどの場合 UTF-8 標準ヘッダーと互換性がありますが、以下の再編集を参照してください。

再編集:次回のために。簡単なマントラを覚えておいてください: "N'DUUH!"; 「UTF-8は絶対に使わないで!」


I18N

この種の問題に対する一般的な解決策は、たとえばgettextを使用して、問題を完全に取り除くことです。

gettext を使用すると、通常loc(char *)、翻訳ツール固有のコードの大部分を抽象化する関数になります。だから、代わりに

#include <iostream>

int main () {
  std::cout << "瓜田李下" << std::endl;
}

あなたが持っているだろう

#include <iostream>

#include "translation.h"

int main () {
  std::cout << loc("DEEPER_MEANING") << std::endl;
}

そして、でzh.po

msgid DEEPER_MEANING
msgstr "瓜田李下"

もちろん、次のようにすることもできますen.po

msgid DEEPER_MEANING
msgstr "Still waters run deep"

これは拡張可能であり、gettext パッケージには、変数などを使用して文字列を拡張するためのツールが含まれているかprintf、さまざまな文法を説明するために を使用できます。


3番目のオプション

ファイル エンコーディング、ファイル エンディング、バイト オーダー マーク、およびその他の種類の問題について、さまざまな要件を持つ複数のコンパイラに対処する必要はありません。MinGWまたは同様のツールを使用してクロスコンパイルすることが可能です。

このオプションにはいくつかの設定が必要ですが、将来のオーバーヘッドと頭痛の種を大幅に削減できる可能性があります。

于 2012-04-27T06:39:48.290 に答える
2

エラーメッセージは問題がインクルードファイルにあることを示しているため、インクルードファイルは通常のUTF-8ですが、コンパイラースイッチのためにコンパイラーはそれらをUTF-16として扱いたいと考えています。

したがって、解決策は常にソースを最初に UTF-8 に変換することだと思います。おそらくメイクファイルにあります。または、他のエンコーディングのインクルード ファイルを含まないソリューションを見つけるには...

編集: システムソースファイルに非ASCII文字が含まれていない場合に限り、GBエンコーディングが機能する可能性があります。その後、問題なく GB エンコードされていることをコンパイラーに伝えることができます。

于 2012-04-27T06:43:25.157 に答える
0

コンパイラはヘッダー ファイルを UTF-16 として読み取ろうとするため、これは機能しませんが、そうではありません。

于 2012-04-27T06:38:46.043 に答える
-1

UTF-16 はバイトのエンコーディングではありません。これは、基本ストレージ ユニットが 16 ビットであるエンコーディングです。

UTF-16 をバイト シーケンスで格納する場合は、UTF-16BE と UTF-16LE のどちらかを選択する必要があります。

于 2012-04-27T06:36:09.653 に答える