为什么我可以使用多个字符串字面量构建一个字符串?

3
#include <iostream>
#include <string>

int main() {
    std::string str = "hello " "world" "!";
    std::cout << str;
}

以下代码可以编译、运行并打印:

你好,世界!

查看实时演示


似乎字符串字面量正在被串联在一起,但有趣的是这不能使用 operator + 实现:
#include <iostream>
#include <string>

int main() {
    std::string str = "hello " + "world";
    std::cout << str;
}

这将编译失败。
查看实时


为什么语言会有这种行为?我的理论是,这使得可以使用多个#include语句构造字符串,因为#include语句必须单独成行。这种行为是由于语言语法的简单可能实现的,还是因为为解决问题而添加的异常情况?

错误信息已经说得很清楚了,不是吗? - P0W
4
因为它是"C/C++"而不是"Java"。 - devnull
@devnull,dup 只覆盖了问题的一半,问题还在于为什么 * 字符串文字 * + * 字符串文字 * 不起作用,这一点并未被 dup 覆盖。 - Shafik Yaghmour
5个回答

10

相邻的字符串字面值会被连接起来,我们可以在C++标准草案的第2.2翻译阶段的第6段看到:

相邻的字符串字面值令牌将被连接起来。

在另一种情况下,没有定义operator+以获取两个*const char**。

至于为什么,这来自于C,我们可以查看国际标准—编程语言—C的基本原理,其中第6.4.5字符串字面值中写道:

一个字符串可以通过使用反斜杠-换行符行续进行多行延续,但这要求字符串的续行从下一行的第一个位置开始。为了允许更灵活的布局,并解决一些预处理问题(参见§6.10.3),C89委员会引入了字符串字面值连接。将两个连续的字符串字面值粘贴在一起,没有中间的空字符,以形成一个组合的字符串字面值。C语言的这个添加允许程序员扩展一个字符串字面值超过物理行的结尾,而不必使用反斜杠-换行机制,从而破坏程序的缩进方案。没有引入显式的连接运算符,因为连接是词法结构而不是运行时操作。

如果没有这个特性,您将不得不执行以下操作,以延续多行的字符串字面值:

   std::string str = "hello \
world\
!";

看起来相当难看。


7

就像 @erenon 所说的,编译器会将多个字符串文字合并为一个。如果您想要使用多行文本,这尤其有帮助:

cout << "This is a very long string-literal, "
        "which for readability in the code "
        "is divided over multiple lines.";

然而,当您使用 operator+ 尝试将字符串字面量连接在一起时,编译器会抱怨因为没有定义两个 char const *operator+。这个操作符已经针对 string 类(完全不同于 C-strings)进行了定义,所以以下写法是合法的:

string str = string("Hello ") + "world";

2
编译器会自动将字符串文字连接成一个字符串。

0

当编译器看到 "hello " + "world"; 时,它会寻找一个接受两个 const char* 的全局 + 运算符... 由于默认情况下没有这样的运算符,因此编译失败。

"hello " "world" "!" 被编译器解析为单个字符串。这使您可以在多行上编写连接的字符串。


0
在第一个例子中,连续的字符串文字在编译开始之前被魔法般地连接起来。编译器看到一个单一的文字,就像你写了 "hello world!" 一样。
在第二个例子中,一旦编译开始,这些文字就变成了静态数组。你不能对两个数组应用 +。
“为什么语言会有这种行为呢?”
这是 C 的遗留问题,它来自于内存是宝贵资源的时代。它允许你进行相当多的字符串操作,而不需要动态内存分配(像更现代的习惯用法 std::string 通常做的那样);代价是一些相当古怪的语义。

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