我可以配置`stdin`来读取c ++字符串吗?

时间:2018-04-05 14:06:19

标签: c++ scanf stdin

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

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

1 个答案:

答案 0 :(得分:0)

我不确定这是多么可移植,但至少在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)的类似方法很有吸引力,但似乎通过对{返回的值调用fileno()返回文件描述符{1}}无效(在我的系统上为-1)。