C 如何在freopen(“out.txt”、“a”和stdout)之后将输出重定向回屏幕 #包括 int main(){ printf(“这进入屏幕\n”); freopen(“out.txt”,“a”,stdout); printf(“这将转到out.txt”); freopen(“/dev/stdout”,“a”,stdout); printf(“这也应该进入屏幕,但不\n”); 返回0; }

C 如何在freopen(“out.txt”、“a”和stdout)之后将输出重定向回屏幕 #包括 int main(){ printf(“这进入屏幕\n”); freopen(“out.txt”,“a”,stdout); printf(“这将转到out.txt”); freopen(“/dev/stdout”,“a”,stdout); printf(“这也应该进入屏幕,但不\n”); 返回0; },c,posix,stdout,C,Posix,Stdout,我调用freopen将stdout重定向到out.txt,然后在文件上打印一些内容,现在我想将它重定向回屏幕,但是freopen(“/dev/stdout”,“a”,stdout);不起作用。使用ANSI C或POSIX系统调用有什么方法可以做到这一点吗?不幸的是,似乎没有什么好方法: 最好的建议是在这种情况下不要使用freopen。一般来说,你不能。你已经关闭了文件,可能是管道之类的。它不能重新开放。您可能已经保存了stdout值,然后为其分配一些fopen,然后关闭它并将旧值复制回来。例如

我调用freopen将stdout重定向到out.txt,然后在文件上打印一些内容,现在我想将它重定向回屏幕,但是freopen(“/dev/stdout”,“a”,stdout);不起作用。使用ANSI C或POSIX系统调用有什么方法可以做到这一点吗?

不幸的是,似乎没有什么好方法:


最好的建议是在这种情况下不要使用freopen。

一般来说,你不能。你已经关闭了文件,可能是管道之类的。它不能重新开放。您可能已经保存了
stdout
值,然后为其分配一些fopen,然后关闭它并将旧值复制回来。例如:

#include <stdio.h>

int main() {
    printf("This goes to screen\n");
    freopen("out.txt", "a", stdout);
    printf("This goes to out.txt");
    freopen("/dev/stdout", "a", stdout);
    printf("This should go to screen too, but doesn't\n");

    return 0;
}
Mike Weller在下面的评论中建议stdout可能并不总是可写的。在这种情况下,这样做可能会有所帮助:

FILE *o = stdout;
stdout=fopen("/tmp/crap.txt","a");
printf("Oh no!\n");
fclose(stdout);
stdout = o;

另一种编辑:如果您使用它来重定向子进程的输出,就像您在其他地方的评论所建议的那样,您可以在fork之后重定向它。

我想不出一种跨平台的方式来实现这一点,但是在GNU/Linux系统(可能还有其他兼容POSIX的系统)上,您可以
freopen(“/dev/tty”,“a”,stdout)
。这就是你想要做的吗?

使用
fdopen()
dup()
以及
freopen()

我不确定你是否能在别处可靠地完成这项任务

确实有效的可疑代码 下面的代码在Solaris 10和MacOS X 10.6.2上运行,但我不确定它是否可靠。结构分配可能适用于Linux glibc,也可能不适用于Linux glibc

int old_stdout = dup(1);  // Preserve original file descriptor for stdout.

FILE *fp1 = freopen("out.txt", "w", stdout);  // Open new stdout

...write to stdout...   // Use new stdout

FILE *fp2 = fdopen(old_stdout, "w");   // Open old stdout as a stream

...Now, how to get stdout to refer to fp2?
...Under glibc, I believe you can use:

fclose(stdout);    // Equivalent to fclose(fp1);
stdout = fp2;      // Assign fp2 to stdout
// *stdout = *fp2;   // Works on Solaris and MacOS X, might work elsewhere.

close(old_stdout);   // Close the file descriptor so pipes work sanely
强积金 (警告:未测试的代码-置信度太高。此外,假设您使用C99编译器编写的所有代码,主要是因为我在第一次需要变量时声明变量,而不是在函数的开头。)


警告:

请注意,如果原始程序作为
/original\u program>文件调用
/original\u program | grep something
(带重定向输出)或从
cron
作业运行,然后打开
/dev/tty
通常不适合作为重新打开标准输出的方式,因为原始标准输出不是终端

另外,请注意,如果在派生和执行子程序之前使用了标准输出重定向,并且在父程序中恢复了原始标准输出,则操作顺序是错误的。您应该分叉,然后调整子级的I/O(仅限),而不修改父级的I/O。

以下代码(SwapIOB)用于要存储的测试台中 用于与预期结果文件进行比较的标准输出流

背景:文件流使用存储在20个IOB条目数组中的_IOB结构进行管理。这包括标准输出流。IOB存储在一个数组中。创建文件时,应用程序代码将获取该数组中某个元素的ptr。然后,应用程序代码将该ptr传递给操作系统以处理I/O调用。因此,操作系统本身并不包含或依赖自己指向应用程序IOB的指针

要求:运行测试台时,应用程序发出的标准输出消息应重新定向到文件。但是,在测试模块完成后,stdout消息应该重新重定向到控制台

此例程经过测试,目前在Windows XP/Pro系统上使用

#include "mprintf.h"

int main()
{
    mprintf("This goes to screen\n");
    FILE *fp1 = fopen("out.txt", "w");
    set_default_stream(fp1);
    mprintf("This goes to out.txt\n");
    fclose(fp1);
    set_default_stream(stdout);
    mprintf("This should go to screen too, but doesn't\n");

    return 0;
}
应用程序代码使用的SwapIOB()类似于:

void SwapIOB(FILE *A, FILE *B) {

    FILE temp;

    // make a copy of IOB A (usually this is "stdout")
    memcpy(&temp, A, sizeof(struct _iobuf));

    // copy IOB B to A's location, now any output
    // sent to A is redirected thru B's IOB.
    memcpy(A, B, sizeof(struct _iobuf));

    // copy A into B, the swap is complete
    memcpy(B, &temp, sizeof(struct _iobuf));

}  // end SwapIOB;
在Windows上,您可以打开“CONOUT$”


如果将stdout重定向到起始位置,这可能不起作用。

除了stdio在某些实现下可能无法以可靠的方式写入之外。Mike Weller可能是。我已尝试提供替代解决方案。这将在重定向或管道传输到另一个进程时中断。只有我fork()的最后一个进程需要重定向到屏幕。这对我的案子很有效。霍夫曼,当然这对你的案子来说已经足够好了,所以我把这个评论给那些会发现问题的人,当整个事情被重定向或者根本没有tty的时候,他们可能会关心这个案子。我同意,哈克。我喜欢下面Jonathan Leffler的解决方案,其中我们有一个printf包装器和一个默认流。这是一个非常好的解决方案,而且是跨平台的(据我所知)。您的第一个建议似乎是正确的方法,但Patrick的建议要简单得多,可以满足我的需要。我没有测试你的答案,但我认为它应该也适用于linux。谢谢你的回答。fprintf(fp,…)对我来说不是一个选项,因为我在子进程上使用exec()。霍夫曼,如果您使用exec(假设您首先使用fork,如果它是子进程),那么为什么不在分叉后进行重定向呢?这实际上是一个很好的解决方案,霍夫曼。您甚至可以使用变量参数宏来包装printf来简化此过程。这只需要一句话。第二个建议,即。第一个建议也适用于Linux(Ubuntu16LTS)。欢迎使用stackoverflow!为什么使用
sizeof(struct\u iobuf)
而不是
sizeof(FILE)
?您的解决方案不允许我还原stderr。对我有用。@cegprakash你为stdin打开了CONIN$吗?我只是在使用freopen(“test1.txt”,“r”,stdin);过了一段时间,我想做freopen(“test2.txt”,“r”,stdin),但stdin仍然指向第一个文件。
#include "mprintf.h"
#include <stdarg.h>

static FILE *default_fp = 0;

void set_default_stream(FILE *fp)
{
    default_fp = fp;
}

int mprintf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);

    if (default_fp == 0)
        default_fp = stdout;

    int rv = vfprintf(default_fp, fmt, args);

    va_end(args);
    return(rv);
 }
#ifndef MPRINTF_H_INCLUDED
#define MPRINTF_H_INCLUDED

#include <stdio.h>

extern void set_default_stream(FILE *fp);
extern int  mprintf(const char *fmt, ...);

#endif
#include "mprintf.h"

int main()
{
    mprintf("This goes to screen\n");
    FILE *fp1 = fopen("out.txt", "w");
    set_default_stream(fp1);
    mprintf("This goes to out.txt\n");
    fclose(fp1);
    set_default_stream(stdout);
    mprintf("This should go to screen too, but doesn't\n");

    return 0;
}
void SwapIOB(FILE *A, FILE *B) {

    FILE temp;

    // make a copy of IOB A (usually this is "stdout")
    memcpy(&temp, A, sizeof(struct _iobuf));

    // copy IOB B to A's location, now any output
    // sent to A is redirected thru B's IOB.
    memcpy(A, B, sizeof(struct _iobuf));

    // copy A into B, the swap is complete
    memcpy(B, &temp, sizeof(struct _iobuf));

}  // end SwapIOB;
FILE *fp;

fp = fopen("X", "w");

SwapIOB(stdout, fp);

printf("text to file X");

SwapIOB(stdout, fp);

fclose(fp);

printf("text to console works, again!");
freopen("test.txt", "w", stdout);
printf("this goes to test.txt");
freopen("CONOUT$", "w", stdout);
printf("this goes to the console\n");