WindowsとLinuxの間に移植可能なソースコードレベルであり、国際化をうまく処理するC ++プログラムを作成するには、IMHOで考慮する必要がある3つの主要なエンコーディングがあります。
- C ++ソースコードエンコーディング。
- 外部データエンコーディング。
- 文字列とリテラルのエンコーディング。
C ++ソースコードの場合、少なくとも標準入力とワイド文字列リテラルがWindowsプラットフォームで動作する必要がある場合は、BOM付きUTF-8を置き換える方法はありません。 BOMなしでUTF-8を使用すると、MicrosoftのVisual C ++コンパイラはソースコードのWindows ANSIエンコーディングを採用します。これはUTF-8を介した出力には適していますstd::cout
が、限られた範囲でのみ機能します(Windowsコンソールウィンドウにはバグがあります)。ただし、viaを入力するとstd::cin
機能しません。
外部データの場合、UTF-8は次のようになります。これ事実上標準。
しかし、内部リテラルと文字列はどうですか?ここにあります。印象UTF-8で狭い文字列エンコーディングは、Linuxで一般的なルールです。しかし、最近2人が異なる主張をしました。ある人は、Linuxの国際アプリケーションでは、内部文字列の普遍的な規則がUTF-32であると主張し、もう1人は単にこの点でUnixとLinuxの間に不特定の違いがあると主張します。
この分野のWindows/Linuxの違いを抽象化する小さなライブラリを趣味で少し修正する人として私は...具体的なお問い合わせ
- プログラムで文字列を表現するための一般的なLinuxルールは何ですか?
私はこの質問™に実際の答えがあるほど非常に一般的な共通の規則があると確信しています。
Linux方式で文字列を反転する方法を示す例(UTF-8を直接使用することは複雑ですが、Linuxの事実上標準関数を介して実行されると推定されています)もお勧めします。つまり、質問としてこのC++ Linuxの一般バージョンは何ですか?プログラム(与えられたコードはC ++の狭いテキスト実行文字セットであるLatin-1用です):
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
#define STATIC_ASSERT( cond ) static_assert( cond, #cond )
int main()
{
string line;
if( getline( cin, line ) )
{
static char const aSingleChar[] = "æ";
STATIC_ASSERT( sizeof( aSingleChar ) - 1 == 1 );
reverse( line.begin(), line.end() );
cout << line << endl;
}
}
答え1
あなたの質問はかなり広いので、これは部分的な答えです。
C ++では、「実行文字セット」を定義します(実際には2つの狭い文字セットと2つの広い文字セットがあります)。
ソースファイルに以下が含まれている場合:
char s[] = "Hello";
次に、実行されたエンコードに基づいて文字列リテラル内の文字の数値バイト値を見つけます。 (ホロ広いワイド文字定数に割り当てられた数値には、適用エンコーディングが適用されますL'a'
。 )
これはすべて、コンパイルプロセスでソースコードファイルを最初に読み込むプロセスの一部として発生します。内部に入ると、C++ 文字は追加の意味のないバイトにすぎません。 (タイプ名はchar
C派生言語で最悪の誤った名前の1つであることに違いありません!)
C++11 にはリテラルu8""
とu""
OK の部分的な例外があります。U""
結果文字列要素の値(つまり、結果の値はグローバルに明示的でプラットフォームに依存しません)ですが、これは影響しません。ソースコードを入力してください説明します。
良いコンパイラは次のことを許可する必要があります。指定するソースコードはエンコードされているので、友達がEBCDICシステムからプログラムテキストを送信しても問題はありません。 GCCには次のオプションがあります。
-finput-charset
:入力文字セット、つまりソースコードファイルがエンコードされる方法-fexec-charset
: 実行文字セット、つまり文字列リテラルがエンコードされる方法-fwide-exec-charset
: 広い実行文字セット、つまり広い文字列リテラルをエンコードする方法
変換にはGCCが使用されるため、サポートされているiconv()
すべてのエンコーディングをiconv()
これらのオプションと組み合わせて使用できます。
私以前に書いたC ++標準は、テキストエンコーディングを処理するためのいくつかの不透明なツールを提供しています。
例:char s[] = "Hello";
ソースファイルがASCII(例:コードを入力ASCIIです)。その後、コンパイラはそれを読み、99
解釈するc
などの作業を行います。文字通りの意味で見ればと72
読んで解釈するH
。これで、実行されたエンコード(ASCIIまたはUTF-8の場合)H
によって決定されたバイト値が配列に保存されます。72
を書くと、\xFF
コンパイラはそれを読み99 120 70 70
、デコードし、配列\xFF
に書き込みます。255
答え2
外部表現の場合、UTF-8は確かに標準です。一部の8ビットエンコーディングは依然として強力であり(主にヨーロッパでは)、一部の16ビットエンコーディングは依然として強力ですが(主に東アジアでは)ゆっくり終了しているレガシーエンコーディングであることは明らかです。 UTF-8はUNIX標準であるだけでなく、Web標準でもあります。
内部表現において、そんなに圧倒的な基準はありません。周りを見回すと、いくつかのUTF-8、いくつかのUCS-2、いくつかのUTF-16、およびいくつかのUCS-4が見つかります。
- UTF-8の利点は、汎用表現と一致し、ASCIIの親セットであることです。特に、ヌル文字がヌルバイトに対応する唯一のエンコーディングです。これは、C API(UNIXシステム呼び出しと標準ライブラリ関数を含む)がある場合に重要です。
- UCS-2は歴史の遺物です。固定幅エンコーディングとみなされるので魅力的ですが、Unicode全体を表さないという点が邪魔になります。
- UTF-16の主な評判はJavaおよびWindows APIにあります。 Unix用にプログラムする場合、Unix API(UTF-8など)はWindows APIよりも適しています。 UTF-16などのAPIと対話するように設計されたプログラムのみがUTF-16を使用する傾向があります。
- UCS-4は固定幅エンコーディングのように見えるので魅力的です。問題はそうではないということです。文字の組み合わせにより、固定幅のUnicodeエンコーディングはありません。
- しかも
wchar_t
。問題は、一部のプラットフォームでは2バイト、他のプラットフォームでは4バイト、それが表す文字セットが指定されていないことです。 Unicodeが事実上の標準文字セットになるにつれて、新しいアプリケーションは避けられる傾向がありますwchar_t
。
UNIXの世界で最も重要な引数は、通常UTF-8を指すUNIX APIとの互換性です。しかし、普遍的ではないため、ライブラリが別のエンコーディングをサポートする必要があるかどうかについてはいかいいえ答えはありません。
この点に関して、Unixバリアントの間に違いはありません。Mac OS Xは分解文字を好む。正規化された表現を得るには、そうしたいかもしれません。 OSX では一部の作業が節約されますが、他の unice では重要ではありません。
UTF-8にはBOMのようなものはありません。バイトオーダーマークは、スーパーバイトサイズのエンコーディングにのみ意味があります。 UTF-8でエンコードされたファイルがU + FEFF文字で始まる必要があるという要件は、一部のMicrosoftアプリケーションにのみ適用されます。
答え3
一部の人々は、Linux国際アプリケーションの内部文字列の普遍的な規則がUTF-32であると主張しています。
これは、= UTF-16(Windowsとの互換性のために)を定義するWindows C(++)コンパイラとは異なり、wchar_t
GCCが文字をUTF-32として定義することを示します。wchar_t
WCHAR
あなたできるwchar_t
便利な場合は内部で使用できます。ただし、POSIX APIはWindowsなどのワイド文字を使用するように書き換えられていないため、* nix世界ではWindows世界ほど一般的ではありません。
UTF-8を内部的に使用すると、「ニュートラルエンコーディング」ルーチンに適しています。たとえば、タブ区切りのスプレッドシートをCSVに変換するプログラムを考えてみましょう。 ASCII文字\t
、、,
および特に処理する必要があり"
ますが、ASCII以外の範囲のすべてのバイト(ISO-8859-1文字またはUTF-8コード単位を表すかどうか)はそのままコピーできます。
趣味でこの領域のWindows/Linuxの違いを抽象化するように設計された小さなライブラリを使って少しの作業をしている人として、
クロスプラットフォームコードを書く際の多くの迷惑の1つは、WindowsではUTF-16を使いやすく、UTF-8は使いにくいということです。しかし、Linuxでは、その逆の場合も同様です。次の関数を作成して処理します。
FILE* fopen_utf8(const char* filename, const char* mode)
{
#ifdef _WIN32
std::wstring wfilename = ConvertUtf8ToUtf16(filename);
std::wstring wmode = ConvertUtf8ToUtf16(mode);
return _wfopen(wfilename.c_str(), wmode.c_str());
#else
return fopen(filename, mode);
#endif
}