web-dev-qa-db-ja.com

C ++コンパイラは、文字列リテラル文字エスケープで2桁を超える16進数を検討し始めたのはいつですか。

C++には(生成された)リテラル文字列があり、\x表記を使用してエスケープする必要のある文字を含めることができます。例えば:

char foo[] = "\xABEcho";

ただし、g ++(問題がある場合はバージョン4.1.2)はエラーをスローします。

test.cpp:1: error: hex escape sequence out of range

コンパイラは、Ec文字を先行する16進数の一部と見なしているようです(16進数のように見えるため)。 4桁の16進数はcharに収まらないため、エラーが発生します。明らかに、ワイド文字列リテラルL"\xABEcho"の場合、最初の文字はU + ABECで、その後にL"ho"が続きます。

これは過去数十年の間にいつか変わったようで、私は気づかなかった。古いCコンパイラは\xの後の2 16進数のみを考慮し、それ以上は検討しないとほぼ確信しています。

これに対する1つの回避策を考えることができます。

char foo[] = "\xAB""Echo";

しかし、それは少し醜いです。だから私は3つの質問があります:

  • これはいつ変更されましたか?

  • コンパイラがワイド文字列リテラルで2桁を超える16進エスケープしか受け入れないのはなぜですか?

  • 上記より扱いにくい回避策はありますか?

57
Greg Hewgill

GCCは 標準に従って のみです。 #877 :「各[...] 16進エスケープシーケンスは、エスケープシーケンスを構成できる最も長い文字シーケンスです。」

私の質問に対する答えを見つけました:

  • C++は常にこのようにしてきました(Stroustrupの第3版を確認しましたが、以前はありませんでした)。 K&R 1st editionは\xについてまったく言及していませんでした(その時点で使用可能な唯一の文字エスケープは8進数でした)。 K&R第2版は次のように述べています。

    '\xhh'
    

    ここでhhは1つ以上の16進数字(0 ... 9、a ... f、A ... F)です。

    したがって、この動作はANSI C以降に発生しているようです。

  • コンパイラーは、ワイド文字列リテラルとして2文字以上しか受け入れられない可能性がありますが、これにより文法が不必要に複雑になります。

  • 実際、それほど厄介な回避策はありません。

    char foo[] = "\u00ABEcho";
    

    \uエスケープは、常にfour16進数を受け入れます。

更新:ほとんどのASCII文字は(何らかの理由で)を使用して指定することが許可されていないため、\u\u。GCCからの抜粋です:

/* The standard permits $, @ and ` to be specified as UCNs.  We use
     hex escapes so that this also works with EBCDIC hosts.  */
  else if ((result < 0xa0
            && (result != 0x24 && result != 0x40 && result != 0x60))
           || (result & 0x80000000)
           || (result >= 0xD800 && result <= 0xDFFF))
    {
      cpp_error (pfile, CPP_DL_ERROR,
                 "%.*s is not a valid universal character",
                 (int) (str - base), base);
      result = 1;
    }
21
Greg Hewgill

これを解決するには、次の文字も\ xnnで指定します。残念ながら、[a..f]の範囲にcharがある限り、これを使用する必要があります。例。 「\ xnneceg」は「\ xnn\x65\x63\x65g」に置き換えられます

4
mike b.

C++は常にこのようになっていると確信しています。とにかく、 CHAR_BITは8より大きい場合があります。その場合、'\xABE'または'\xABEc'は有効である可能性があります。

3
Ben Voigt