【问题标题】:C++: Is there a standard definition for end-of-line in a multi-line string constant?C++:多行字符串常量中的行尾是否有标准定义?
【发布时间】:2016-10-05 23:54:20
【问题描述】:

如果我有一个多行字符串 C++11 字符串常量,例如

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

是否定义了行终止符/分隔符由哪些字符组成?

【问题讨论】:

  • 它由源文件中的任何内容组成。这是一个字面意思:内容就是您输入的内容。对于具有明确定义的 EOL 要求(例如 HTTP)的服务器来说,这还不够:您应该将 \r\n 用于 HTTP、邮件等。
  • @Cheersandhth.-Alf - 并非所有网站访问者都拥有 128k 代表或者是该领域的专家。只要问题是主题性的而不是重复的,无论提问者的代表如何,它都是可以接受的。
  • 在这个问题上存在(或至少是)实际的实现分歧。当以阅读标准和编写编译器为生的人彼此意见不一致时,这几乎不是“完全入门的新手”。
  • @Cheersandhth.-Alf:我的 146k 代表高到足以让我不同意你的观点吗?
  • @Cheersandhth.-Alf:我不同意。该标准明确指出,在阶段 1 和 2 中执行的任何转换都将被还原。这些转换明确包括新行字符的引入。规范的措辞是明确的,如果您忽略不是字符序列的行尾指示符,它甚至是有意义的(您可能在 Windows 上想要 CR-LF 对)。有人认为值得提交 DR,但 3 年多后仍未解决。我并不是说你错了,我只是在暗示你的结论并不像你想象的那么明显。

标签: c++ c++11 portability


【解决方案1】:

目的是原始字符串文字中的换行符映射到单个 '\n' 字符。这个意图没有表达得那么清楚 应该是,这导致了一些混乱。

引用的是 2011 ISO C++ 标准。

首先,这是它映射到单个 '\n' 字符的证据。

第 2.14.5 节 [lex.string] 第 4 段中的注释说:

[ 注意: 原始字符串文字中的源文件换行符会导致 结果执行中的换行string-literal。假设没有 在以下示例中,行首的空格, 断言会成功:

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

——尾注]

这清楚地表明换行符映射到单个'\n' 特点。它也符合 g++ 6.2.0 和观察到的行为 clang++ 3.8.1(在 Linux 系统上使用源文件完成的测试 Unix 风格和 Windows 风格的行尾)。

鉴于注释中明确说明的意图和两个人的行为 流行的编译器,我会说依赖它是安全的——尽管它 看看其他编译器如何处理这个问题会很有趣。

然而,按照规范措辞的字面理解 标准很容易导致不同的结论,或者至少 有一些不确定性。

第 2.5 节 [lex.pptoken] 第 3 段说(强调添加):

在开头和结尾的双引号字符之间 原始字符串,在第 1 阶段和第 2 阶段执行的任何转换 (三元组、通用字符名称和线拼接) 被还原;此回复应在任何 d-char 之前适用, r-char,或分隔括号被识别。

翻译阶段在 2.2 [lex.phases] 中指定。在第一阶段:

物理源文件字符被映射,在一个 实现定义的方式,以基本的源字符集 (为行尾指示符引入换行符)如果 必要的。

如果我们假设物理源文件字符到 基本字符集和换行符的引入是 “transformations”,我们可以合理地得出结论,例如, Windows 格式的原始字符串文字中间的换行符 源文件应该等同于\r\n 序列。 (我能想象 这对特定于 Windows 的代码很有用。)

(这种解释确实会导致系统出现问题,其中 行尾指示符不是字符序列,例如 其中每一行是一个固定宽度的记录。这样的系统很少见 这些天。)

作为"Cheers and hth. - Alf"'s answer 指出,有一个开放的 Defect Report 对于这个问题。 2013年提交的,现在还没有 解决了。​​

就个人而言,我认为混淆的根源是“任何”这个词 (强调如前所述):

在原始的首尾双引号字符之间 字符串,any 在阶段 1 和 2 (trigraphs, 通用字符名称和线拼接) 被还原;这 reversion 应在任何 d-charr-char 或分隔符之前应用 括号已标识。

当然是物理源文件字符到 可以合理地想到基本的源字符集 作为一个转换。带括号的子句“(三元组, 通用字符名称和线拼接)”似乎是有意的 指定要还原的哪些转换,但是 要么试图改变“转换”这个词的含义 (标准没有正式定义)或与使用相矛盾 “任何”这个词。

我建议将“任何”一词改为“确定”将表达 明显的意图更清楚:

在原始的首尾双引号字符之间 字符串,在阶段 1 和 2 中执行的某些转换(三元组, 通用字符名称和线拼接)被还原;这 reversion 应在任何 d-charr-char 或分隔符之前应用 括号已标识。

这个措辞会更清楚地表明“三元组, 通用字符名称和线拼接”是唯一的 要还原的转换。 (并非所有事情都完成了 在翻译阶段 1 和 2 被还原,只是那些特定的 列出的转换。)

【讨论】:

  • 请注意,对于行是记录的文件系统,即没有数据表示换行符的文件系统,出于参数原因的解释完全失败。很久以前我没有使用过这样的系统,但我记得,HP 3000 上的 MPE/IV 就是这样。我记得模糊地读过VAX也是那个,但是虽然我作为学生使用过VAX机器,但我不记得了,对不起。但是,要点是,C++ 规则不能没有将换行符转换为\n。因为否则将无法在这些系统上运行。
  • 另请注意,在我的回答中引用了一个关于此的开放核心语言问题。
  • 您在上面写道:“这清楚地表明换行符映射到单个 '\n' 字符。”我同意你的说法,但有一个例外:标准中的说法令人困惑,因为它使用术语new-line,就好像它会引入一个换行符,而不是转义序列`\n'。你能对此发表评论吗?
  • @Belloc - 我不确定我是否理解您的评论。原始字符串文字中的换行符会产生换行符。它不会创建\n 转义序列,但它等效于\n 转义序列。
  • 好的,我想我能理解你在说什么。但是,正如您在上面所写的那样,标准中究竟在哪里说换行符映射到单个 \n 字符?我相信您知道[lex.string]/3 只是一个注释。
【解决方案2】:

标准似乎表明:

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);

尾注 ]

5 [ 示例: 原始字符串

R"a(
)\
a"
)a"

相当于"\n)\\\na\"\n"

【讨论】:

  • 不清楚。这只表示换行符映射到换行符。它没有说明如果源文件包含 \r 会发生什么。
  • @EJP:在标准中查找“翻译阶段”。显然你认为源文件字符直接变成文字。他们没有。
  • @Cheersandhth.-Alf 没有“显然”的意思。这正是我在问题下方的评论中所说的。我很可能错了,但这里还没有出现令人信服的证据。这个答案是迄今为止最接近的。至少他引用了一些东西。
  • @Cheersandhth.-Alf 在 2.5 中它还说“在原始字符串的初始和最终双引号字符之间,在阶段 1 和 2 中执行的任何转换(三字符、通用字符名称和线拼接)被还原”
  • 另外,示例和注释是non-normative,这对我来说有点模棱两可
【解决方案3】:

注意:自发布答案以来,问题已发生重大变化。只剩下一半,即纯 C++ 方面。此答案中的网络焦点解决了原始问题的“将多行字符串发送到具有明确定义的行尾要求的服务器”。我一般不追求问题的演变。

在程序内部,换行符的 C++ 标准是\n。这也用于原始文字中的换行符。原始文字没有特殊约定。

通常\n 映射到 ASCII 换行符,即值 10。

我不确定它在 EBCDIC 中映射到什么,但如果需要,您可以检查一下。

然而,在我的印象中,大多数协议使用 ASCII 回车加换行,即 13 后跟 10。这有时被称为 CRLF,在 ASCII 缩写 CR 表示回车和LF 换行。当 C++ 转义映射到 ASCII 时,这只是 C++ 中的 \r\n

您需要遵守所使用协议的要求。

对于普通文件/流 i/o,C++ 标准库负责将内部 \n 映射到主机环境使用的任何约定。这称为文本模式,与不执行映射的二进制模式相反。

对于标准库未涵盖的网络 i/o,应用程序代码必须自己执行此操作,直接或通过某些库函数。


有一个关于此的活跃问题core language defect report #1655“原始字符串文字中的行结尾”,由 Mike Miller 于 2013 年 4 月 26 日提交,他问到,

是否打算将原始字符串文字源中的 CRLF 表示为换行符或原始字符?

由于行尾值因原始文件的编码而异,并且考虑到在某些文件系统中没有行尾编码,而是行作为记录,很明显意图不是按原样表示文件内容——因为这在所有情况下都不可能做到。但据我所知,此 DR 尚未解决。

【讨论】:

  • 这并没有(直接)回答关于原始字符串文字的问题。
  • @TavianBarnes:换行符的 C++ 标准是 \n。我看不出你怎么没看懂。
  • @Alf C++ 标准规定\n 映射到换行符。如果标准中有什么东西可以回答这个问题,或者“将换行符映射到\n”,这不一定是同一件事,你应该引用它。
  • @Cheersandhth.-Alf 如果你的意思是R""" """"""s 之间应该有一个换行符,但它当然不会在 cmets 中呈现)和"\n" 是等价的,你应该明确地说出来(最好提供证据)。
  • @EJP:标准没有说'\n' 映射到换行符。它甚至没有提到换行符。它说'\n' 映射到换行符。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-19
  • 2011-02-14
  • 1970-01-01
  • 2019-01-17
  • 1970-01-01
  • 2011-06-06
  • 1970-01-01
相关资源
最近更新 更多