web-dev-qa-db-ja.com

WindowsでのMBCSとUTF-8の違い

Windowsでの文字セットとエンコーディングについて読んでいます。 Visual Studioコンパイラ(C++用)には、MBCSとUNICODEという2つのコンパイラフラグがあります。それらの違いは何ですか?私が取得していないのは、UTF-8がMBCSエンコーディングと概念的にどのように異なるかです?また、 [〜#〜] msdn [〜#〜] で次の引用を見つけました。

Unicodeは16ビット文字エンコードです

これは、私がユニコードについて読んだものをすべて否定します。 Unicodeは、UTF-8やUTF-16などのさまざまなエンコーディングでエンコードできると思いました。誰かがこの混乱にもう少し光を当てることができますか?

57
Naveen

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。

99
dan04

_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 IB0 AE as C4 E3 as 4D as M

strlenは0x00のみを知っているため、6を取得します。

wcslenは、この16進数の配列がUTF16LEでエンコードされていると見なし、2バイトを1つのWordとしてカウントするため、3ワードを取得します:49 B0AE C4E3 4D

@xiaokaoyが指摘したように、wcslenの有効なターミネーターは00 00のみです。したがって、次のバイトが3でない場合、結果は00になることは保証されません。

16
Jichao

[〜#〜] 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

10
stakx

他の回答の脚注として、MSDNには、ドキュメントがあります TCHAR.Hの汎用テキストマッピング プリプロセッサディレクティブ_UNICODEおよび_MBCSがさまざまなC/C++型の定義を変更する方法をまとめた便利な表があります。

「ユニコード」および「マルチバイト文字セット」という言い回しに関しては、人々はすでに効果が何であるかを説明しています。どちらも、Microsoftが非常に具体的なことを話すことを強調したいだけです。 (つまり、テキストの国際化に関するマイクロソフト固有でない理解から来る場合に予想されるよりも一般的でなく、Windowsに特有なものを意味します。)これらの正確なフレーズが現れ、独自のセクション/サブセクションを取得する傾向がありますMicrosoftの技術文書の例in Visual C++のテキストと文字列

4
Chris