C ++:在多行string常量中是否有行尾的标准定义?
如果我有一个多行stringC ++ 11string常量如
R"""line 1 line 2 line3"""
是否定义了行结束符/分隔符包含哪些字符?
目的是在原始string文字中的换行符映射到单个'\n'
字符。 这个意图并不是很清楚,这导致了一些混乱。
引用的是2011年的ISO C ++标准。
首先,这是certificate它映射到一个单一'\n'
字符。
第2.14.5节[lex.string]第4段中的说明指出:
[ 注:原始string文字中的源文件换行会导致生成的执行string中出现一个换行符。 在下面的例子中,假设在行首没有空白,assert将成功:
const char *p = R"(a\ b c)"; assert(std::strcmp(p, "a\\\nb\nc") == 0);
– 结束注意 ]
这清楚地表明一个换行符映射到一个单一'\n'
字符。 它也符合观察到的g ++ 6.2.0和clang ++ 3.8.1的行为(在使用Unix风格和Windows风格的行结尾的源文件的Linux系统上进行的testing)。
考虑到在笔记中明确声明的意图以及两个stream行的编译器的行为,我可以说依靠这个是安全的 – 尽pipe看看其他编译器是如何处理这个问题会很有趣。
但是,对标准的规范措辞的文字阅读很容易导致不同的结论,或者至less是一些不确定性。
第2.5节[lex.pptoken]第3段说(强调加):
在原始string的初始和最终双引号字符之间,在阶段1和阶段2 (三字母,通用字符名称和行拼接)中执行的任何转换都被还原; 在任何d-char , r-char或划定的括号之前,这个返回应该适用。
翻译的阶段在2.2 [lex.phases]中规定。 在阶段1:
如果需要,物理源文件字符以实现定义的方式映射到基本源字符集(为行尾指示符引入新行字符)。
如果我们假设物理源文件字符到基本字符集的映射和新行字符的引入是“ 变形 ”,我们可以合理地得出结论,例如,在一个原始string文本中间的一个换行符Windows格式的源文件应该等同于一个\r\n
序列。 (我可以想象,对于特定于Windows的代码是有用的。)
(这种解释确实会导致系统中尾部指示符不是字符序列的问题,例如每行是固定宽度的logging,这种系统现在很less见)。
正如“干杯和欢呼 – 阿尔夫”的回答指出的那样,这个问题有一个公开的缺陷报告 。 它在2013年提交,尚未解决。
就我个人而言,我认为混淆的根源是“任何”一词(强调如前所述):
在原始string的初始和最终双引号字符之间,在阶段1和阶段2 (三字母,通用字符名称和行拼接)中执行的任何转换都被还原; 在任何d-char , r-char或划定的括号之前,这个返回应该适用。
物理源文件字符到基本源字符集的映射当然可以合理地认为是一种转换 。 加括号的子句“(trigraphs,universal-character-names,and line splicing)”似乎是用来指定要转换的转换,但要么试图改变“转换”这个词的含义没有正式定义),或者与使用“任何”这个词相矛盾。
我build议把“任何”这个词改成“确定”,会更清楚地expression出明显的意图:
在原始string的初始和最终双引号字符之间,在阶段1和2(三字母,通用字符名称和行拼接)中执行的某些转换被还原; 在任何d-char , r-char或划定的括号之前,这个返回应该适用。
这个措词会使得“三字母,普遍字符名称和行拼接”是唯一要转换的转换更加清晰。 (并非所有在翻译阶段1和2中完成的任何事情都被还原,只是那些特定的列出的转换。)
标准似乎表明:
R"""line 1 line 2 line3"""
相当于:
"line 1\nline 2\nline3"
从2.14.5 C ++ 11标准的string文字 :
4 [ 注意:原始string文字中的源文件换行会导致生成的执行string文字出现换行符。 在下面的例子中,假设在行首没有空白,assert将成功:
const char *p = R"(a\ b c)"; assert(std::strcmp(p, "a\\\nb\nc") == 0);
– 结束注意 ]
5 [ 例如:原始string
R"a( )\ a" )a"
相当于
"\n)\\\na\"\n"
。
注意:自答案发布以来,问题发生了很大变化。 它只剩下一半,即纯粹的C ++方面。 在这个答案中的networking焦点解决了原来的问题“发送一个多行string到服务器端定义明确的需求”。 一般来说,我不追逐问题的进化。
在程序的内部,换行符的C ++标准是\n
。 这也用于原始文字中的换行符。 原始文字没有特别的约定。
通常\n
映射到ASCII换行符,即值10。
我不确定它在EBCDIC中的映射关系,但是如果需要的话可以检查一下。
然而,在networking上,我的印象是,大多数协议使用ASCII回车加换行符,即13和10。这有时被称为CRLF ,用于回车的ASCII缩写CR和换行的LF。 当C ++转义符映射为ASCII时,这在C ++中是简单的\r\n
。
您需要遵守您使用的协议的要求。
对于普通文件/streami / o,C ++标准库负责将内部映射到主机环境使用的任何约定。 这被称为文本模式 ,而不是二进制模式 ,其中不执行映射。
对于没有被标准库覆盖的networkingI / O,应用程序代码必须直接或通过某些库函数自己完成。
关于这个问题 , 核心语言缺陷报告#1655 “原始string中的行结尾”由Mike Miller 2013-04-26提交,他在这里提出一个积极的问题 ,
“例如,原始string文本来源中的CRLF将被表示为换行符还是原始字符?
由于行结束值根据原始文件的编码而不同,并且考虑到在某些文件系统中没有行结束符的编码,而是行作为logging,很明显,其目的不是将文件内容表示为 -是 – 因为在所有情况下都是不可能的。 但据我所知,这个DR还没有解决。