【问题标题】:c++: How to pass a raw string to a function like evaluate( "2+2\0+2" )?c++:如何将原始字符串传递给像评估(“2+2\0+2”)这样的函数?
【发布时间】:2016-07-26 18:19:14
【问题描述】:

编辑::std::string infix="2+2\0+2"; 如何将其传递给函数evaluate(std::string s){cout << s}? => 2+2+2 ?

EDIT2:: \0 是一个NULL 字符;我的语法检查函数从字符串中读取每个字符,如果它不同于数字或运算符,则会引发异常。我想读取空字符并引发异常,但evaluate("2+2\0+2") 返回4


我正在用 c++11 编写一个带有测试的简单计算器,支持中缀表示法。

我有一个函数int evaluate( const std::string & infix ),它根据我的字符串计算结果(即evaluate( "((-3+--4*-(-19+5)))" ) 返回53)。一切正常,直到...

当我创建一些测试时,我可以写ASSERT_EQ(6, evaluate("2+2+2"))。但是当我写ASSERT_EQ(6, evaluate("2+2\0+2") 时,一切都出错了(这应该抛出一个exception,但它返回4)。

那么如何将一个字符数组传递给一个函数,而不知道它的大小并且其中包含空字符?当const char cstr[] = "2+\0+2"; evaluate(cstr); 没有发送完整的数组时:(

【问题讨论】:

  • 字符串文字中不能有空字节。 C++ 不知道数组的长度 (char[]),所以它假设它以 \0 结尾。
  • 正是这个问题!那么当你有一个像evaluate( std::string or any other const*char )这样的公共函数并且有人想写一个像ASSERT_..(evaluate( "\0" ))这样的测试时如何保护自己??
  • @Zereges 这是错误的。您可以在字符串文字中很好地包含空字节,并且数组的大小是其类型的一部分。 std::string 只是没有模板构造函数可以直接取入数组,所以要小心一点。

标签: c++ string templates c++11 null


【解决方案1】:

问题不在于函数,而在于调用者。要从包含空字节的字符串文字构造 std::string,您需要使用接收有关字符串大小信息的重载之一。

一个这样的重载 (number 4 here) 接受 char 指针和大小。由于字符串文字是char 数组,因此您可以使用函数模板检索它们的大小:

template <std::size_t N>
std::string make_string(char const (&lit)[N]) {
    return {lit, N};
}

...并因此使用它:

ASSERT_EQ(6, evaluate(make_string("2+2\0+2")));

您也可以使用相同的原理通过重载函数来直接处理字符串文字:

template <std::size_t N>
auto evaluate(char const (&lit)[N]) {
    return evaluate({lit, N});
}

【讨论】:

  • 是的!现在如何在不使用预处理器的情况下重载构造函数以使其默认拥有? string("2+2) 调用 string("2+2",3)?有可能吗?
  • @MrAker 证明甚至不需要宏。我想知道为什么我没有看到更快。
  • 仍然,我不能写评估(“2+2\0+2”),我必须写评估(函数(“”)):
【解决方案2】:

我的猜测是您不是要测试“2 plus 2 null_byte plus 2”,而是要测试“2 plus 2 除以零加 2”。

如果是这样,请记住,在 C++ 字符串文字中,您需要输入双反斜杠(因为反斜杠被用作许多不可输入字符的转义字符)。

试试

ASSERT_EQ(6, evaluate("2+2\\0+2"))

或者,因为您使用的是 C++11

ASSERT_EQ(6, evaluate(R"2+2\0+2"))

使用“原始”字符串文字

【讨论】:

  • 是的!但是当测试它的人不好并且想向我表明我的程序很糟糕(!),并且不会在他或她的字符串前加上任何“R”时,如何保护自己免受这些人和人们的行为?
  • 如果人们不知道如何编写 C++,你就无法保护自己免受使用 C++ 编写测试的人的伤害!如果他们不犯这个错误,他们就会犯其他错误。如果您的测试代码是由非开发人员编写的,请让他们在文本文件中写入“2+2+2=6”和“2+2\0+2=error”之类的内容,并拥有一个测试工具运行文件中的所有测试。但是不要让它们靠近你的 C++ 编译器!
  • @MrAker divide 符号是 /(看看你的数字键盘)。使用它而不是 `\`,你的所有问题都会消失。
  • @ZDF,很好发现。 +1
  • XD @ZDF 我想在字符串中发送一个空字符,而不是除法字符 XXXXXDDDDD
【解决方案3】:

当 const char cstr[] = "2+/0+2";评估(cstr);不发送完整的数组:(

您可以使用std::string 的构造函数,它接受迭代器范围,例如:

// Using macro
#define ARR_TO_STR(a) std::string(std::cbegin(a), std::cend(a))

// And template function
template <typename T, size_t N>
std::string ArrToStr( T (&t)[N] ) {
    return std::string(std::cbegin(t), std::cend(t));
}

int main()
{
   ASSERT_EQ(6, evaluate(ArrToStr("2+\0+2")))
}

【讨论】:

  • 是的,但是在测试期间我不创建任何变量,我只有一个函数,我可以向其发送字符串或任何其他字符数组。 :((((((((((((((()))
猜你喜欢
  • 1970-01-01
  • 2016-05-22
  • 2018-10-03
  • 2017-05-31
  • 2012-05-07
  • 1970-01-01
  • 1970-01-01
  • 2010-11-05
相关资源
最近更新 更多