从C转发stdin和stdout

Chr*_*utz 62 c redirect stdio

我想重开stdinstdout(也许stderr当我在它)的文件句柄,从而使未来的呼叫printf()putchar()还是puts()会去到一个文件,以及未来的呼叫getc()和这种将来自一个文件.

1)我不想永久丢失标准输入/输出/错误.我可能希望稍后在程序中重用它们.

2)我不想打开新的文件句柄,因为这些文件句柄必须要么传递很多,要么全局传递(不寒而栗).

3)如果我无法帮助,我不想使用任何open()fork()其他系统相关的功能.

所以基本上,这样做是否有效:

stdin = fopen("newin", "r");
Run Code Online (Sandbox Code Playgroud)

而且,如果确实如此,我怎样才能得到原来的价值stdin?我是否必须将其存放在一个FILE *以后才能将其取回?

bk1*_*k1e 80

为何使用freopen()?C89规范的答案见以下部分的尾注之一<stdio.h>:

116.的主要用途freopen功能是改变(与标准文本流相关联的文件stderr, stdinstdout),如那些标识符不必是可修改的左值,由所述返回的值fopen函数可以被分配.

freopen通常被滥用,例如stdin = freopen("newin", "r", stdin);.这不比便携式便携fclose(stdin); stdin = fopen("newin", "r");.两个表达式都尝试分配stdin,但不保证可以赋值.

正确的使用方法freopen是省略任务:freopen("newin", "r", stdin);

  • 那怎么恢复呢? (12认同)
  • @AbiusX 我不确定这有多便携,但在 POSIX 环境下,你可以用另一种方式来做到这一点 - 通过使用 `dup2()` 更改底层句柄的含义:http://linux.die.net/man/3 /冲洗。这将让您在替换之前复制 STDOUT 句柄,然后您可以复制回来。只要记住`fflush()`。这里有一个用于分叉的示例:http://stackoverflow.com/questions/9405985/linux-3-0-executing-child-process-with-piped-stdin-stdout (2认同)

Joh*_*n T 16

我想你正在寻找类似的东西 freopen()


小智 10

这是Tim Post方法的修改版本; 我使用/ dev/tty而不是/ dev/stdout.我不知道为什么它不能用于stdout(这是一个到/ proc/self/fd/1的链接):

freopen("log.txt","w",stdout);
...
...
freopen("/dev/tty","w",stdout);
Run Code Online (Sandbox Code Playgroud)

通过使用/ dev/tty,输出将重定向到启动应用程序的终端.

希望这些信息很有用.


gah*_*ooa 9

os函数dup2()应该提供你需要的东西(如果没有提到你需要的东西).

更具体地说,您可以将stdin文件描述符dup2()转换为另一个文件描述符,使用stdin执行其他操作,然后在需要时将其复制回来.

dup()函数复制打开的文件描述符.具体来说,它使用F_DUPFD常量命令值为fcntl()函数提供服务的备用接口,第三个参数为0.重复的文件描述符与原始文件描述符共享任何锁定.

成功时,dup()返回一个与原始文件具有以下共同点的新文件描述符:

  • 相同的打开文件(或管道)
  • 相同的文件指针(两个文件描述符共享一个文件指针)
  • 相同的访问模式(读,写或读/写)


Tim*_*ost 9

freopen("/my/newstdin", "r", stdin);
freopen("/my/newstdout", "w", stdout);
freopen("/my/newstderr", "w", stderr);

... do your stuff

freopen("/dev/stdin", "r", stdin);
...
...
Run Code Online (Sandbox Code Playgroud)

这针在我的圆钉 - 方孔 - o-meter上达到峰值,你想要完成什么?

编辑:

请记住,对于每个新创建的进程,stdin,stdout和stderr都是文件描述符0,1和2.freopen()应该保持相同的fd,只需为它们分配新的流.

因此,确保实际执行您希望它执行的操作的一种好方法是:

printf("Stdout is descriptor %d\n", fileno(stdout));
freopen("/tmp/newstdout", "w", stdout);
printf("Stdout is now /tmp/newstdout and hopefully still fd %d\n",
   fileno(stdout));
freopen("/dev/stdout", "w", stdout);
printf("Now we put it back, hopefully its still fd %d\n",
   fileno(stdout));
Run Code Online (Sandbox Code Playgroud)

我相信这是freopen()的预期行为,你可以看到,你仍然只使用三个文件描述符(和相关的流).

这将覆盖任何shell重定向,因为shell没有任何重定向.然而,它可能会打破管道.您可能希望确保为SIGPIPE设置处理程序,以防您的程序发现自己位于管道的阻塞端(而不是FIFO,管道).

因此,./your_program --stdout /tmp/stdout.txt --stderr /tmp/stderr.txt应该可以使用freopen()轻松完成,并保持相同的实际文件描述符.我不明白为什么你一旦改变它们就需要把它们放回去?当然,如果有人通过任何一个选项,他们会希望它一直持续到程序终止?