与引号串联会导致错误

Concatenation with quote causes error

本文关键字:错误      更新时间:2023-10-16

这是一个无法在我的机器上编译的代码。我有一个解决方法,但我不了解该行为以及为什么解决方法

#include <string>
using namespace std;
int main(int argc, char* argv[])
{
  string pdfPath;
  string tempFolder;
  //... both strings are read from config file ...//
  string listPath = tempFolder+"\"+"list";
  string dir = "dir "+"""+pdfPath+"" "+"/b >"+" ""+listPath+""";
  //... all the other stuff ...//
}

此代码无法编译并给出此错误:

|71|error: invalid operands of types 'const char [5]' and 'const char [2]' to binary 'operator+'|

这是它所指的行: 字符串 dir = "dir

"+"\"+pdfPath+"\" "+"/b>"+" \"+listPath+"\";

但是,如果我将其更改为:

string dir = "dir "+string(""")+pdfPath+"" "+"/b >"+" ""+listPath+""";

为什么它关心一个地方的"""建设,而不关心其他地方?我之前(在同一程序中(与"""连接过,它没有引起任何问题。这工作得很好:

string dir = "dir "+pdfPath+"" "+"/b >"+" ""+listPath+""";

虽然它有那个""".

不能

使用 C 或 C++ 中的 + 连接 C 字符串文本。 但是你可以使用任何运算符来连接它们:

string dir = "dir " """ + pdfPath + "" " "/b >" " "" + listPath + """;

编译器足够聪明,可以将相邻的字符串文字放在一起,并且串联没有运行时成本。

您可以将 c 字符串连接到std::string

std::string dir; dir = dir + "dir " + pdfPath;

但是,不能使用 C++ 中的operator+()将 C 字符串连接到 C 字符串

"one" + "two"告诉编译器将第一个 c 字符串的指针值添加到第二个 c 字符串。 std::string("one") + std::string("two")连接两个字符串。如果你想连接两个c字符串,你必须"one" "two"<</p>

div class="answers">

这里有几个重叠的问题,所以你可能会发现乍一看很难理解,你可能会对整体事物产生错误的印象。

最重要的是(并非详尽无遗(:

  1. 在 C 和 C++ 中,文字"mom"不是字符串。这实际上是"指向常量字符数组的指针">
  2. 有一些**指针算术",所以你可以给指针添加一个5,但是没有办法把两个指针加在一起
  3. 当你有一个像std::string这样的类时,该类可以提供自己的运算符,包括+-
  4. 编译器在解析a + b + c + d + e + ..等没有运算符比其他运算符具有更高优先级的表达式时,可以按任何顺序分析表达式

我们先来看看第四点。

鉴于

string dir = "dir "+"""+pdfPath+"" "+"/b >"+" ""+listPath+""";

如何评价?所有+运算符都是相等的。没有一个具有更高的优先级。唯一可以肯定的是,=赋值将最后执行。跨编译器执行的常见方法是先求值或先右手求值。因此,一个编译器就可以:

string dir = ("dir "+("""+(pdfPath+("" "+("/b >"+(" ""+(listPath+"""))))));

其他可以做到:

string dir = (((((("dir "+""")+pdfPath+"" ")+"/b >")+" "")+listPath)+""");

(或者他们可以以他们喜欢的任何其他顺序方式制作(
现在,在第二个示例中,请注意,在最里面的参数中,有一个:

("dir "+""")

因此,一些编译器可以在此处报告"无法添加指向指针的指针"的错误。请参阅上述列表中的第 2 期。

另一方面,左手优先编译器在这里不会失败,因为在第一个示例中,最里面的部分是

(listPath+""")

而列表路径是一个std::string。请参阅上面列表中的第 3 点。 std::string定义一个运算符 +,用于处理字符串到指针的添加。此运算符再次返回std::string。因此,最里面的括号会产生一个字符串,该字符串将被添加到字符串中,依此类推。所以 - 没有编译错误。

但这完全依赖于编译器,因为评估的顺序没有严格定义。

解决此问题并涵盖所有编译器的最简单方法是将所有部分转换为字符串:

string dir = string("dir ") + string(""") + ...

等等。但是,这很烦人。因此,有许多库允许您使用某种"格式字符串",这些字符串用作填充"数据"的"模式"。这使您不必担心,并使代码更清晰。

示例可能如下所示:

string dir = format_me( "dir "%s" /b > "%s"", pdfPath, listPath);
string dir = format_me( "dir "{0}" /b > "{1}"", pdfPath, listPath);

或类似流:

buffer buff;
buff << "dir "" << pdfPath << "" /b > "";
buff << listPath << """;
string cmd = buff.toString();

%s{0}标记是将放置参数的"占位符"。这些示例是人为的,与任何库无关。检查您的平台和库以找到您最喜欢的格式化程序。例如,Boost为您提供stringstream类。它的工作原理类似于最后一个类似流的流

始终仔细阅读错误消息。您收到的错误消息足够清晰

|71|错误:类型为"常量字符 [5]"和"常量字符"的操作数无效 [2]' 到二进制 'operator+'

在此声明中

string dir = "dir "+"""+pdfPath+"" "+"/b >"+" ""+listPath+""";

您正在尝试添加字符串文字"dir """"。第一个类型为 const char [5],第二个具有 - const char [2](字符串文字包括终止零 '\0'(。

这就是你要做的

"dir "+"""

但是,数组没有内置运算符 +。您不能添加数组。

在第二种情况下

string dir = "dir "+string(""")+pdfPath+"" "+"/b >"+" ""+listPath+""";

你添加

"dir "+string(""")

这是一个字符串文本,对象类型为 std::string。类 std::string 对 std::string 类型的操作数具有重载operator +(更准确地说,对于 std::string 类型的对象,存在重载运算符 + 的非成员函数(。由于类 std::string 有一个转换构造函数,可以将 const char * 类型的对象转换为 std::string 类型的对象,因此编译器将此转换应用于字符串文字,并为类 std::string 的对象调用运算符 +。

实际上,编译器将此表达式转换为以下内容

string( "dir " ) + string(""") // call of the conversion constructor
operator + ( string( "dir " ), string(""") ) // call of the operator