我可以配置"stdin"以从 c++ 字符串中读取吗?

Can I configure `stdin` to read from a c++ string?

本文关键字:quot 读取 字符串 以从 配置 stdin 我可以 c++      更新时间:2023-10-16

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

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

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

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

#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()(如此处使用)尝试类似的方法很诱人,但似乎通过对从fmemopen()返回的值调用fileno()返回的文件描述符无效(在我的系统上为 -1)。