【问题标题】:C++ redirect or disable stdio temporarilyC++ 临时重定向或禁用 stdio
【发布时间】:2016-05-23 07:57:20
【问题描述】:

在 MacOS X 下的 C++ 项目中,我们使用 stdio 与客户端进行交互。然而,我们使用的 dylib 也使用 stdio 来打印“打开的日志文件”。这破坏了我们的客户和应用程序之间的所有通信。我查看了将 stdio 重定向到文件或暂时禁用 stdio 的示例。然而,我们未能成功。

那么,我们如何在与 dylib 交互时暂时禁用或重定向 stdio。

【问题讨论】:

    标签: c++ stdio


    【解决方案1】:
    void RedirectStandardStreamsToDEVNULL(int *_piOriginalSTDIN_FILENO, int *_piOriginalSTDOUT_FILENO, int *_piOriginalSTDERR_FILENO)
    {
            //flushing pending things before redirection.
            //fflush(stdin);
            fflush(stdout);
            fflush(stderr);
    
            *_piOriginalSTDIN_FILENO = dup(STDIN_FILENO);
            *_piOriginalSTDOUT_FILENO = dup(STDOUT_FILENO);
            *_piOriginalSTDERR_FILENO = dup(STDERR_FILENO);
    
            int devnull = open("/dev/null", O_RDWR);
            dup2(devnull, STDIN_FILENO);
            dup2(devnull, STDOUT_FILENO);
            dup2(devnull, STDERR_FILENO);
            close(devnull);
    }
    void RestoreStandardStreams(int *_piOriginalSTDIN_FILENO, int *_piOriginalSTDOUT_FILENO, int *_piOriginalSTDERR_FILENO)
    {
            //flushing pending things before restoring.
            //fflush(stdin);
            fflush(stdout);
            fflush(stderr);
    
            dup2(*_piOriginalSTDIN_FILENO, STDIN_FILENO);
            dup2(*_piOriginalSTDOUT_FILENO, STDOUT_FILENO);
            dup2(*_piOriginalSTDERR_FILENO, STDERR_FILENO);
    }
    
    void myfunction()
    {
        int iOriginalSTDIN_FILENO = -1;
        int iOriginalSTDOUT_FILENO = -1;
        int iOriginalSTDERR_FILENO = -1;
        RedirectStandardStreamsToDEVNULL(&iOriginalSTDIN_FILENO, &iOriginalSTDOUT_FILENO, &iOriginalSTDERR_FILENO);
    
    //all of your code which prints to stdout or stderr will be directed to /dev/null
    
        RestoreStandardStreams(&iOriginalSTDIN_FILENO, &iOriginalSTDOUT_FILENO, &iOriginalSTDERR_FILENO);
    
    }
    

    重要的一点是从代码中识别在 dylib 中调用的函数。现在,用上述重定向和恢复函数围绕这些函数。

    【讨论】:

    • 谢谢sameerkn,我们尝试了解决方案。我们注意到,第一次运行代码时,“打开日志文件”文本从控制台中消失了。但下一次,它仍然存在并导致与客户端应用程序的通信崩溃。我认为您的方法可以处理所有三种 stdio 使用情况;所以我希望它会起作用。
    • 另外,如果我写 close(STDOUT_FILENO);fclose(stdout); 日志文本永远不会被打印。之后有没有办法恢复标准输出?
    • dup2 本身会关闭Redirect 函数内的 STDOUT_FILENO。您是否正确地将所有对 dylib 的调用嵌套在 RedirectRestore 函数下?
    • 这是我调用函数的方式:` int iOriginalSTDIN_FILENO = -1; int iOriginalSTDOUT_FILENO = -1; int iOriginalSTDERR_FILENO = -1; RedirectStandardStreamsToDEVNULL(&iOriginalSTDIN_FILENO, &iOriginalSTDOUT_FILENO, &iOriginalSTDERR_FILENO); std::string a = listCardTypeAndSlots(); RestoreStandardStreams(&iOriginalSTDIN_FILENO, &iOriginalSTDOUT_FILENO, &iOriginalSTDERR_FILENO); std::cout
    • 还有一点。如果我在 restore 和 std::cout 之间暂停 5 秒,日志会在 5 秒后打印。所以,当我向 std::cout 写一些非常简单的东西时,日志会被写入控制台。
    【解决方案2】:

    OSX 是一个 POSIX 系统,与所有 POSIX 系统一样,标准输出是文件描述符STDOUT_FILENO(这是一个定义为1 的宏)。

    您可以做的是duplicateSTDOUT_FILENO 到另一个文件描述符,open 一个临时文件并将临时文件复制(使用dup2)作为STDOUT_FILENO。然后,只要有输出到标准输出(使用纯 write、C printf 或 C++ std::cout),它将被放入临时文件中。

    完成临时“重定向”后,您只需将保存的标准输出(来自第一个dup 调用)复制回STDOUT_FILENO。并关闭并删除临时文件。

    类似于以下内容:

    int saved_stdout = dup(STDOUT_FILENO);
    
    int temp_file = open("/tmp/temp_stdout", O_WRONLY, 0600);
    dup2(temp_file, STDOUT_FILENO);  // Replace standard out
    
    // Code here to write to standard output
    // It should all end up in the file /tmp/temp_stdout
    
    dup2(saved_stdout, STDOUT_FILENO);  // Restore old standard out
    close(temp_file)
    unlink("/tmp/temp_stdout");  // Remove file
    

    【讨论】:

    • 谢谢 Joachim,我们尝试了您的建议。不幸的是,它仍然将“打开的日志文件”打印到 stdio。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    • 2010-12-05
    • 2017-10-03
    • 2019-07-29
    • 1970-01-01
    • 2018-07-15
    相关资源
    最近更新 更多