web-dev-qa-db-ja.com

C ++:複数行の文字列定数の行末の標準的な定義はありますか?

次のような複数行の文字列C++ 11文字列定数がある場合

R"""line 1
line 2
line3"""

ラインターミネーター/セパレーターを構成する文字は定義されていますか?

39
Mark Harrison

その意図は、生の文字列リテラルの改行が単一の'\n'文字にマップされることです。この意図はあるべきように明確に表現されておらず、混乱を招いています。

引用は2011 ISO C++標準に準拠しています。

まず、これが単一の'\n'文字にマッピングされるという証拠です。

セクション2.14.5 [Lex.string]のパラグラフ4の注記は、次のように述べています。

[Note:生の文字列リテラルのソースファイルの改行は、結果の実行で改行になりますstring-literal。次の例の行の先頭に空白がないと仮定すると、アサートは成功します。

    const char *p = R"(a\
    b
    c)";
    assert(std::strcmp(p, "a\\\nb\nc") == 0);

end note]

これは、改行が単一の'\n'文字にマッピングされていることを明確に示しています。また、g ++ 6.2.0およびclang ++ 3.8.1の観測された動作(UnixスタイルおよびWindowsスタイルの行末を持つソースファイルを使用してLinuxシステムで行われたテスト)にも一致します。

メモで明確に述べられている意図と2つの一般的なコンパイラの動作を考えると、これに依存しても安全だと思います-他のコンパイラが実際にこれを処理する方法を見るのは興味深いでしょうが。

ただし、標準の規範的表現を文字どおりに読むと、簡単に別の結論につながる可能性があります。

セクション2.5 [Lex.pptoken]パラグラフ3は次のように述べています(強調を追加):

生文字列の最初と最後の二重引用符文字の間で、フェーズ1および2で実行されるany変換(trigraphs 、ユニバーサル文字名、行のスプライシング)が元に戻されました。この復帰は、任意のd-charr-char、または区切り括弧が識別される前に適用されます。

翻訳のフェーズは2.2 [Lex.phases]で指定されています。フェーズ1:

物理ソースファイルの文字は、必要に応じて、実装定義の方法で、基本的なソース文字セット(行末インジケーターの改行文字を導入)にマップされます。

物理的なソースファイルの文字の基本文字セットへのマッピングと改行文字の導入を "transformations"とすると、たとえば、途中の改行はWindows形式のソースファイル内の未加工の文字列リテラルのは、\r\nシーケンスと同等である必要があります。 (Windows固有のコードに役立つことは想像できます。)

(この解釈は、各行が固定幅レコードである場合など、行末標識が文字のシーケンスではないシステムで問題を引き起こします。このようなシステムは最近ではまれです。)

"Cheers and hth。-Alf" 's answer が指摘しているように、この問題には未解決の Defect Report があります。 2013年に提出され、まだ解決されていません。

個人的には、混乱の根源は「any」という言葉(強調は前と同じように追加)だと思います。

生の文字列の最初と最後の二重引用符文字の間で、フェーズ1および2で実行されるany変換(trigraphs 、ユニバーサル文字名、行のスプライシング)が元に戻されました。この復帰は、任意のd-charr-char、または区切り括弧が識別される前に適用されます。

確かに、物理ソースファイルの文字から基本ソース文字セットへのマッピングは、transformationと考えるのが妥当でしょう。括弧で囲まれた「(trigraphs、universal-character-names、and line splicing)」はwhich変換を元に戻すことを意図しているようですが、どちらかがWordの意味を変更しようとしています変換」(標準では正式に定義されていません)、または「any」という単語の使用に矛盾しています。

「any」という単語を「特定の」に変更すると、明白な意図がより明確に表現されることをお勧めします。

生の文字列の最初と最後の二重引用符文字の間で、フェーズ1と2で実行された特定の変換(トリグラフ、ユニバーサル文字名、およびラインスプライシング)が元に戻されます。この復帰は、任意のd-charr-char、または区切り括弧が識別される前に適用されます。

この言葉遣いは、「トリグラフ、ユニバーサル文字名、およびラインスプライシング」だけが元に戻される変換であることをより明確にします。 (変換フェーズ1と2で行われたすべてが元に戻るわけではなく、リストされた特定の変換だけが元に戻ります。)

27
Keith Thompson

標準はそれを示しているようです:

R"""line 1
line 2
line3"""

以下と同等です。

"line 1\nline 2\nline3"

C++ 11標準の2.14.5文字列リテラルから:

4 [注:生の文字列リテラルのソースファイルの改行は、結果の実行で改行になります文字列リテラル。次の例の行の先頭に空白がないと仮定すると、アサートは成功します。

const char *p = R"(a\
b
c)";
assert(std::strcmp(p, "a\\\nb\nc") == 0);

end note]

5 [例:生の文字列

R"a(
)\
a"
)a"

"\n)\\\na\"\n"と同等です。

16
R Sahu

注:回答が投稿されてから、質問は大幅に変更されました。残りの半分、つまり純粋なC++の側面だけが残っています。この回答でのネットワークの焦点は、元の質問の「行末の要件が明確に定義されたサーバーへの複数行の文字列の送信」に対応しています。私は一般的に質問の進化を追跡しません。

プログラムの内部では、改行のC++標準は\nです。これは生のリテラルの改行にも使用されます。生のリテラルには特別な規則はありません。

通常、\nは、ASCII linefeedにマップされます。値は10です。

それがEBCDICで何にマップされるかはわかりませんが、必要に応じて確認できます。

ただし、ネットワーク上では、ほとんどのプロトコルでASCIIキャリッジリターン+ラインフィード、つまり13の後に10が続くもの)を使用しているようです。これはと呼ばれることもあります[〜# 〜] crlf [〜#〜]、ASCIIキャリッジリターンの省略形CRとLF改行の後ろ。 C++エスケープはASCII=にマップされます。これは単にC++では\r\nです。

使用しているプロトコルの要件に従う必要があります。

通常のファイル/ストリームI/Oの場合、C++標準ライブラリが内部\nをホスト環境が使用する規則にマッピングします。これは、マッピングが実行されないバイナリモードとは対照的に、テキストモードと呼ばれます。

標準ライブラリではカバーされないネットワークI/Oの場合、アプリケーションコードは、直接または一部のライブラリ関数を介して、これを自分で行う必要があります。


これについてアクティブな問題があります コア言語欠陥レポート#1655 「生の文字列リテラルの行末」、Mike Miller 2013-04- 26、彼が尋ねるところ、

は、たとえば、生の文字列リテラルのソースのCRLFが改行文字または元の文字として表されることを目的としています?

行末の値は元のファイルのエンコードによって異なり、一部のファイルシステムではは行末のエンコードではなく行のレコードのエンコードではなく、行をレコードとして認識しているため、意図はファイルの内容をそのまま表すことではありません–それはすべての場合に不可能であるためです。しかし、私が見る限り、このDRはまだ解決されていません。