将一个输出到控制台的函数的输出重定向为字符串。

12

假设我们有一个函数,它将文本打印到控制台中,但我们无法控制其源代码,但我们可以调用它。例如:

void foo() {
    std::cout<<"hello world"<<std::endl; 
    print_to_console(); // this could be printed from anything
}

不改变该函数本身,能否将上述函数的输出重定向到一个字符串?

我不是在寻找通过终端执行此操作的方法。


1
你是在询问是否暂时重定向 std::cout,还是暂时重定向函数 print_to_console() 的输出,仅限于此次调用或函数 foo() - Martin York
3个回答

27

可以做到。这里是一个小演示:

#include <sstream>
#include <iostream>

void print_to_console() {
    std::cout << "Hello from print_to_console()" << std::endl;
}

void foo(){
  std::cout<<"hello world"<<std::endl; 
  print_to_console(); // this could be printed from anything
}
int main()
{
    std::stringstream ss;

    //change the underlying buffer and save the old buffer
    auto old_buf = std::cout.rdbuf(ss.rdbuf()); 

    foo(); //all the std::cout goes to ss

    std::cout.rdbuf(old_buf); //reset

    std::cout << "<redirected-output>\n" 
              << ss.str() 
              << "</redirected-output>" << std::endl;
}

输出:

<redirected-output>
hello world
Hello from print_to_console()
</redirected-output>

查看在线演示


2
哇,我完全忘记了你可以这样做。 - chris
2
auto *old_buf?指针是必要的吗?auto 不会丢弃指针。 - Praetorian
@Praetorian:不需要使用 *。我之前是出于习惯而写的 :P - Nawaz
5
但我认为你不应该使用auto_ptr*:p - chris
4
如果使用printf、puts、write等函数会发生什么? - Andre Kostur
@AndreKostur:看看我的另一个解决方案(发布为另一个答案)。 :-) - Nawaz

7

@Andre在我的第一个回答中的评论中提出了以下问题:

如果他们使用printf、puts、write等函数会发生什么?- Andre Kostur

对于printf,我想到了以下解决方案。它只适用于POSIX,因为fmemopen仅在POSIX上可用,但是如果您需要便携式解决方案,则可以使用临时文件 - 这将更好。基本思路将是相同的。

#include <cstdio>

void print_to_console() {
    std::printf( "Hello from print_to_console()\n" );
}

void foo(){
  std::printf("hello world\n");
  print_to_console(); // this could be printed from anything
}

int main()
{
    char buffer[1024];
    auto fp = fmemopen(buffer, 1024, "w");
    if ( !fp ) { std::printf("error"); return 0; }

    auto old = stdout;
    stdout = fp;

    foo(); //all the std::printf goes to buffer (using fp);

    std::fclose(fp);
    stdout = old; //reset

    std::printf("<redirected-output>\n%s</redirected-output>", buffer);
}

输出:

<redirected-output>
hello world
Hello from print_to_console()
</redirected-output>

Online Demo.


不要扔扳手进去...但这是否必定适用于流和标准输出?也许重新打开文件描述符1可能适用于两种情况。(仍然假设POSIX) - Andre Kostur

1
class buffer
    : public std::streambuf
{
public:
    buffer(std::ostream& os)
        : stream(os), buf(os.rdbuf())
    { }

    ~buffer()
     {
         stream.rdbuf(buf);
     }

private:
    std::ostream& stream;
    std::streambuf* buf;
};

int main()
{
    buffer buf(std::cout);
    std::stringbuf sbuf;

    std::cout.rdbuf(sbuf);

    std::cout << "Hello, World\n";
}

4
如果你想让它符合 RAII 的要求,为什么不试试像这样的写法(http://coliru.stacked-crooked.com/a/71d90cb0a3459b65),可以使客户端代码更简洁。 :-) - Nawaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接