Windowsでの文字セットとエンコーディングについて読んでいます。 Visual Studioコンパイラ(C++用)には、MBCSとUNICODEという2つのコンパイラフラグがあります。それらの違いは何ですか?私が取得していないのは、UTF-8がMBCSエンコーディングと概念的にどのように異なるかです?また、 [〜#〜] msdn [〜#〜] で次の引用を見つけました。
Unicodeは16ビット文字エンコードです
これは、私がユニコードについて読んだものをすべて否定します。 Unicodeは、UTF-8やUTF-16などのさまざまなエンコーディングでエンコードできると思いました。誰かがこの混乱にもう少し光を当てることができますか?
Visual Studioコンパイラ(C++用)には、MBCSとUNICODEという2つのコンパイラフラグがあることに気付きました。それらの違いは何ですか?
Windows APIの多くの関数には、2つのバージョンがあります。1つは(ロケール固有のコードページで)char
パラメーターを受け取り、もう1つは(UTF-16で)wchar_t
パラメーターを受け取ります。
int MessageBoxA(HWND hWnd, const char* lpText, const char* lpCaption, unsigned int uType);
int MessageBoxW(HWND hWnd, const wchar_t* lpText, const wchar_t* lpCaption, unsigned int uType);
これらの関数ペアのそれぞれには、UNICODE
マクロが定義されているかどうかに応じて、接尾辞のないマクロもあります。
#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif
これを機能させるために、TCHAR
タイプを定義して、API関数で使用される文字タイプを抽象化します。
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif
ただし、これは 悪いアイデアでした です。文字タイプは常に明示的に指定する必要があります。
私が取得していないのは、UTF-8がMBCSエンコーディングと概念的にどのように異なるかです?
MBCSは「マルチバイト文字セット」の略です。文字通りの人にとっては、UTF-8が適格だと思われます。
ただし、Windowsでは、「MBCS」はWindows API関数の「A」バージョンで使用できる文字エンコードのみを指します。これには、コードページ932(Shift_JIS)、936(GBK)、949(KS_C_5601-1987)、および950(Big5)が含まれますが、[〜#〜] not [〜#〜]UTF-8。
UTF-8を使用するには、MultiByteToWideChar
を使用して文字列をUTF-16に変換し、関数の「W」バージョンを呼び出し、出力でWideCharToMultiByte
を呼び出す必要があります。これは基本的に「A」関数が実際に行うことであり、これは なぜWindowsはUTF-8をサポートしていないのか のように思えます。
最も一般的な文字エンコーディング をサポートできないことにより、Windows APIの「A」バージョンは役に立たなくなります。したがって、「W」関数を常に使用する必要があります。
Unicodeは16ビット文字エンコードです
これは、私がユニコードについて読んだものすべてを否定します。
MSDNは間違っています。 Unicodeは21ビットのコード化された文字セットで、いくつかのエンコーディングがあり、最も一般的なのはUTF-8、UTF-16、およびUTF-32です。 (GB18030、UTF-7、UTF-EBCDICなど、他のUnicodeエンコードもあります。)
Microsoftが「Unicode」を指すときはいつでも、実際にはUTF-16(またはUCS-2)を意味します。これは歴史的な理由によるものです。 Windows NTは、16ビットで十分だと考えられていたUnicodeの早期採用者であり、UTF-8はプラン9でのみ使用されていました。したがって、UCS-2 was Unicode。
_MBCSおよび_UNICODEは、呼び出すTCHAR.Hルーチンのバージョンを決定するマクロです。たとえば、_tcsclen
を使用して文字列の長さをカウントする場合、プリプロセッサは_tcsclen
を2つのマクロ_MBCSおよび_UNICODEに従って異なるバージョンにマッピングします。
_UNICODE & _MBCS Not Defined: strlen
_MBCS Defined: _mbslen
_UNICODE Defined: wcslen
これらの文字列長カウント関数の違いを説明するために、次の例を検討してください。
GBK(936コードページ)を使用するWindows簡体字中国語版を実行するコンピューターボックスがある場合、gbk-file-encodedソースファイルをコンパイルして実行します。
printf("%d\n", _mbslen((const unsigned char*)"I爱你M"));
printf("%d\n", strlen("I爱你M"));
printf("%d\n", wcslen((const wchar_t*)"I爱你M"));
結果は4 6 3
になります。
GBKでのI爱你M
の16進表現は次のとおりです。
GBK: 49 B0 AE C4 E3 4D 00
_mbslenはこの文字列がGBKでエンコードされていることを知っているため、文字列を正しく解釈して正しい結果を得ることができます4
単語:49
as I
、B0 AE
as 爱
、C4 E3
as 你
、4D
as M
。
strlenは0x00
のみを知っているため、6
を取得します。
wcslenは、この16進数の配列がUTF16LEでエンコードされていると見なし、2バイトを1つのWordとしてカウントするため、3
ワードを取得します:49 B0
、AE C4
、E3 4D
。
@xiaokaoyが指摘したように、wcslen
の有効なターミネーターは00 00
のみです。したがって、次のバイトが3
でない場合、結果は00
になることは保証されません。
[〜#〜] mbcs [〜#〜]は マルチバイト文字セット を意味する文字が(おそらく)1バイト以上にエンコードされている文字セットを記述します。
[〜#〜] ansi [〜#〜]/[〜#〜] ascii [〜#〜 ]文字セットはマルチバイトではありません。
UTF-8ただし、マルチバイトエンコーディングです。任意のUnicode文字を1、2、3、または4オクテット(バイト)のシーケンスとしてエンコードします。
ただし、UTF-8は、Unicode文字セットのいくつかの可能な具体的なエンコーディングのうちの1つにすぎません。特に、UTF-16は別のものであり、たまたまWindows/.NET(IIRC)で使用されているエンコーディングです。 UTF-8とUTF-16の違いは次のとおりです。
UTF-8は、Unicode文字を1、2、3、または4バイトのシーケンスとしてエンコードします。
UTF-16は、ほとんどのUnicode文字を2バイトとしてエンコードし、一部は4バイトとしてエンコードします。
したがって、Unicodeが16ビット文字エンコードであることはnot正しいです。これは、コードポイントU+000000
最大U+10FFFF
。
他の回答の脚注として、MSDNには、ドキュメントがあります TCHAR.Hの汎用テキストマッピング プリプロセッサディレクティブ_UNICODEおよび_MBCSがさまざまなC/C++型の定義を変更する方法をまとめた便利な表があります。
「ユニコード」および「マルチバイト文字セット」という言い回しに関しては、人々はすでに効果が何であるかを説明しています。どちらも、Microsoftが非常に具体的なことを話すことを強調したいだけです。 (つまり、テキストの国際化に関するマイクロソフト固有でない理解から来る場合に予想されるよりも一般的でなく、Windowsに特有なものを意味します。)これらの正確なフレーズが現れ、独自のセクション/サブセクションを取得する傾向がありますMicrosoftの技術文書の例in Visual C++のテキストと文字列