web-dev-qa-db-ja.com

GCCおよびMSVCのC ++ utf-8リテラル

ここに簡単なコードがあります:

#include <iostream>
#include <cstdint>

    int main()
    {
         const unsigned char utf8_string[] = u8"\xA0";
         std::cout << std::hex << "Size: " << sizeof(utf8_string) << std::endl;
          for (int i=0; i < sizeof(utf8_string); i++) {
            std::cout << std::hex << (uint16_t)utf8_string[i] << std::endl;
          }
    }

ここでは、MSVCとGCCで異なる動作が見られます。 MSVCは"\xA0"をエンコードされていないUnicodeシーケンスとして認識し、それをutf-8にエンコードします。したがって、MSVCでは、出力は次のようになります。

C2A0

Utf8ユニコードシンボルU+00A0で正しくエンコードされています。

しかし、GCCの場合は何も起こりません。文字列を単純なバイトとして扱います。文字列リテラルの前にu8を削除しても変更はありません。

両方のコンパイラは、文字列がC2A0に設定されている場合、出力u8"\u00A0";でutf8にエンコードします。

コンパイラの動作が異なるのはなぜですか?

テストに使用したソフトウェア:

GCC 8.3.0

MSVC 19.00.23506

C++ 11

6
toozyfuzzy

どちらも間違っています。

私の知る限り、C++ 17標準は here と言っています:

ナローストリングリテラルのサイズは、エスケープシーケンスおよびその他の文字の総数に、各ユニバーサル文字名のマルチバイトエンコーディング用に少なくとも1つ、および終了 '\ 0'用に1つを加えたものです。

他にもヒントがありますが、これはエスケープシーケンスがマルチバイトではなく、MSVCの動作が間違っていることを示す最も強い兆候であるようです。

現在、調査中としてマークされているチケットがあります。

ただし、UTF-8リテラルについて here とも記載されています。

値が単一のUTF-8コード単位で表現できない場合、プログラムは不正な形式です。

0xA0は有効なUTF-8文字ではないため、プログラムはコンパイルできません。

ご了承ください:

  • u8で始まるUTF-8リテラルは、ナローとして定義されています。
  • \xA0はエスケープシーケンスです
  • \u00A0は、エスケープシーケンスではなく、ユニバーサル文字名と見なされます
2
AtnNn

コンパイラの動作が異なるのはなぜですか?

C++標準の実装を決定した方法により、コンパイラーの動作は異なります。

  • GCCは厳密なルールを使用し、標準をそのまま実装します
  • MSVCは緩いルールを使用し、より実用的な「現実の」種類の方法で標準を実装します

したがって、GCCで失敗したものは、より許容範囲が広いため、通常はMSVCで機能します。そして、MSVCはこれらの問題のいくつかを自動的に処理します。

同様の例を次に示します: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=33167 。それは標準に従いますが、あなたが期待するものではありません。

どちらが正しいかについては、「正しい」の定義が何であるかに依存します。

1
Cosmin

どちらの方法が標準に当てはまるかはわかりません。

MSVCが行う方法は、少なくとも論理的に一貫しており、簡単に説明できます。 3つのエスケープシーケンス\x\u\Uは、入力から取得する16進数字の数(2、4、または8)を除いて、同じように動作します。それぞれがUnicodeコードポイントを定義し、その後、UTF-8にエンコードする必要があります。エンコードせずにバイトを埋め込むと、無効なUTF-8シーケンスが作成される可能性があります。

1
Mark Ransom