C++ 预处理器字符串字面值连接

6
我发现了关于C语言预处理器如何处理字符串字面值连接(阶段6)的这个。然而,我找不到任何关于C++如何处理此问题的信息(C++是否使用C预处理器?)。
我提出这个问题的原因是我有以下代码:
const char * Foo::encoding = "\0" "1234567890\0abcdefg";

其中encoding是类Foo的静态成员。如果没有拼接,我将无法以那种方式编写该字符序列。

const char * Foo::encoding = "\01234567890\0abcdefg";

由于\012的解释方式不同,所以这是完全不同的东西。
我无法访问多个平台,我很好奇上述问题是否总是被正确处理 - 也就是说,我总是会得到{0,'1','2','3',...}

1
只是出于好奇 - 你为什么使用char*而不是std :: string? - Robben_Ford_Fan_boy
1
@David Relihan:为什么有人会使用std::string来表示不可变的字符串常量呢?甚至没有考虑到客户端代码规范可能需要char *(例如某些API)。 - AnT stands with Russia
1
@AndreyT: "为什么有人会使用std::string来表示不可变的字符串常量?" 因为他们想要按字典顺序比较字符串(而且不想考虑它们是否是常量或其他什么因素)? - sbi
7
你可以将它写成 "\000123..."。一个数字转义序列最多只能有三个八进制数字,第四个数字不包括在转义序列中,它是一个普通字符。 - Rob Kennedy
@Rob:我没有想到那个。好的解决方案 :) - ezpz
3个回答

10
该语言(包括 C 和 C++ )没有“预处理器”。作为独立的功能单元,“预处理器”是一个实现细节。源文件的处理方式由所谓的“翻译阶段”定义。在 C 和 C++ 中的一个阶段涉及串联字符串字面量。
对于 C++ 标准,它在2.1中进行了描述。对于C++(C++03),它是第6阶段。

6个相邻的普通字符串文字标记将被连接在一起。相邻的宽字符串文字标记将被连接。


没错,我在寻找一份关于C++的详细文档。但是我没有找到 - 尽管我很容易找到C语言的相关资料。 - ezpz
1
AndreyT - 你忘了提到 "\0" 在字符串字面值合并之前被转换为目标字符集。这是解决问题的关键。 - D.Shawley
1
@D.Shawley:我并不立即理解这个的重要性。你的意思是没有这个\0部分,12部分仍然可以与之合并形成一个八进制字符字面值\012吗?嗯...我认为这里真正重要的部分是第4阶段,而不是第5阶段,当每个字符串字面值被转换为独立的预处理记号时。这一点已经解决了\012的潜在问题,不是吗? - AnT stands with Russia

6
是的,会按照您所描述的方式处理,因为在第5阶段中,

每个字符常量和字符串字面值中的源字符集成员和转义序列都将转换为执行字符集的相应成员(C99 §5.1.1.2/1)

C++03中的语言实际上是相同的:

字符常量和字符串字面值中的每个源字符集成员、转义序列或通用字符名都将被转换为执行字符集的一个成员(C++03 §2.1/5)

因此,在第五阶段中,转义序列(如\0)将被转换为执行字符集的成员,然后在第六阶段连接字符串字面值。


没错,我明白这一点。我的问题是这在C/C++中是否透明。如果是的话,我可以在哪里找到相关文档参考? - ezpz
@ezpz:抱歉,我没注意到你对两者之间的兼容性感兴趣。是的,对于C和C++来说结果是相同的。我已经添加了C++标准中的语言,其实也是同样的意思。你可以在这个问题中找到获取相关标准文档的位置:https://dev59.com/wnVD5IYBdhLWcg3wHnyd - James McNellis
1
+1 因为提到了不同的翻译阶段,这就是为什么 "\0" "12" 不同于 "\012" 的原因。 - D.Shawley

0
由于C++和C标准之间的协议,大多数(如果不是全部)C++实现都使用C预处理器,因此可以肯定地说,C++使用C预处理器。

更准确地说,C++标准和C标准在某些翻译阶段以及预处理器指令方面达成了一致,而且我所知道的每个C++实现都使用了C预处理器。我喜欢保持标准所说的和实现所做的之间的差异。 - David Thornley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接