【问题标题】:Can I configure `stdin` to read from a c++ string?我可以将“stdin”配置为从 C++ 字符串中读取吗?
【发布时间】:2018-09-15 09:31:24
【问题描述】:

我有很多用 C 语言编写的第三方函数,它们的输入来自 stdinscanf()。我已经用 C++ 编写了其他调用 c 函数的函数。现在,我正在准备测试,我想用 C++ 字符串编写输入测试用例。

所以我的问题是,是否有一种方法可以表达stdin 应该从 C++ 字符串而不是标准输入中读取?如果我实现了这一点,那么我可以编写几个输入是 c++ 字符串的测试用例,并且我的 C++ 函数会被透明地调用,这些函数调用 c 函数并期望它们的输入来自 stdin

【问题讨论】:

  • 嗯,你可以从文件重定向输入。
  • freopen?先看看如何从字符串生成文件... No.
  • 如果您可以用 C++ 重写 C 函数,请将它们编写为接受 std::istream & 类型的参数。 istream 有多种类型(ifstream 从文件中读取,istringstream 从字符串中读取,等等)。测试函数所需要做的就是提供一个已适当初始化的适当类型的实例。一般来说,从 stdin 读取的 C 函数不能被强制从标准 C++ 中的字符串读取。
  • c_str。上面的第二个相关链接仅适用于 Linux(POSIX?),但这可能是您需要的。

标签: c++ scanf stdin


【解决方案1】:

我不确定它的可移植性如何,但至少在 Linux 上使用 gcc-6.3,您可以重新分配 stdin 以指向不同的流,然后 scanf() 将透明地使用它,就好像它仍在从中读取一样终点站。如果您想从预先存在的字符串中读取,可以使用 fmemopen() 之类的东西打开新的流,这应该在 POSIX 系统上可用。这允许您从内存块创建FILE*,例如std::string 的内容。

作为说明,以下代码将 scanf() 来自字符串 "String with 3.14159 * 2" 的五个值,就好像它们是从终端输入的一样:

#include <cstdio>
#include <iostream>
#include <string>
#include <unistd.h>

int main(int argc, char *argv[])
{ const std::string input("String with 3.14159 * 2");
  char s0[16], s1[16], s2[8];
  double pi = 3; 
  int two = -2;

  { FILE *old_stdin = stdin;
    FILE* strm = fmemopen((void*)input.c_str(), input.size(), "r");
    stdin = strm;

    scanf("%s %s %lf %s %d", s0, s1, &pi, s2, &two);
    std::cout << "s0=\"" << s0 << "\" s1=\"" << s1 << "\""
              << " pi=" << pi << " s2=\"" << s2 << "\""
              << " two=" << two << std::endl;

    stdin = old_stdin;
    fclose(strm);
  }

  scanf("%12s", s0);
  std::cout << "Stdin: \"" << s0 << "\"" << std::endl;

  return 0;
}

这会产生以下输出:

s0="String" s1="with" pi=3.14159 s2="*" two=2

在将stdin 返回到其正常行为之前,第二个scanf() 等待来自终端的输入。

尝试使用dup2()(如使用here)的类似方法很诱人,但似乎通过对fmemopen()返回的值调用fileno()返回的文件描述符无效(在我的系统上为 -1)。

【讨论】:

    猜你喜欢
    • 2021-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-26
    • 2015-02-28
    • 2011-03-04
    • 1970-01-01
    相关资源
    最近更新 更多