从 C 重新路由 stdin 和 stdout

发布于 2024-07-13 23:38:19 字数 549 浏览 6 评论 0原文

我想重新打开 stdinstdout (也许还有 stderr)文件句柄,以便将来调用 printf()putchar()puts() 将转到文件,并且将来调用 getc() 和这将来自一个文件。

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

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

3) 如果我无法控制,我不想使用任何 open()fork() 或其他依赖于系统的函数。

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

stdin = fopen("newin", "r");

如果有效,我怎样才能取回 stdin 的原始值? 我是否必须将其存储在 FILE * 中并稍后再取回?

I want to reopen the stdin and stdout (and perhaps stderr while I'm at it) filehandles, so that future calls to printf() or putchar() or puts() will go to a file, and future calls to getc() and such will come from a file.

1) I don't want to permanently lose standard input/output/error. I may want to reuse them later in the program.

2) I don't want to open new filehandles because these filehandles would have to be either passed around a lot or global (shudder).

3) I don't want to use any open() or fork() or other system-dependent functions if I can't help it.

So basically, does it work to do this:

stdin = fopen("newin", "r");

And, if it does, how can I get the original value of stdin back? Do I have to store it in a FILE * and just get it back later?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

默嘫て 2024-07-20 23:38:19

为什么使用freopen()? C89 规范在 部分的尾注之一中给出了答案:

116。 freopen 函数的主要用途是更改与标准关联的文件
文本流(stderr
stdinstdout),因为这些标识符不需要
可修改的左值
fopen函数返回
可能会被分配。

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

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

Why use freopen()? The C89 specification has the answer in one of the endnotes for the section on <stdio.h>:

116. The primary use of the freopen function is to change the file associated with a standard
text stream (stderr,
stdin, or stdout), as those identifiers need not be
modifiable lvalues to which the value
returned by the fopen function
may be assigned.

freopen is commonly misused, e.g. stdin = freopen("newin", "r", stdin);. This is no more portable than fclose(stdin); stdin = fopen("newin", "r");. Both expressions attempt to assign to stdin, which is not guaranteed to be assignable.

The right way to use freopen is to omit the assignment: freopen("newin", "r", stdin);

梦过后 2024-07-20 23:38:19

我认为您正在寻找类似 freopen()

I think you're looking for something like freopen()

你怎么敢 2024-07-20 23:38:19

这是 Tim Post 方法的修改版本; 我使用 /dev/tty 而不是 /dev/stdout。 我不知道为什么它不适用于标准输出
(这是 /proc/self/fd/1 的链接):

freopen("log.txt","w",stdout);
...
...
freopen("/dev/tty","w",stdout);

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

希望这些信息有用。

This is a modified version of Tim Post's method; I used /dev/tty instead of /dev/stdout. I don't know why it doesn't work with stdout
(which is a link to /proc/self/fd/1):

freopen("log.txt","w",stdout);
...
...
freopen("/dev/tty","w",stdout);

By using /dev/tty the output is redirected to the terminal from where the app was launched.

Hope this info is useful.

妳是的陽光 2024-07-20 23:38:19

操作系统函数dup2()应该提供您所需要的< /strong> (如果没有引用您所需要的内容)。

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

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

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

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

The os function dup2() should provide what you need (if not references to exactly what you need).

More specifically, you can dup2() the stdin file descriptor to another file descriptor, do other stuff with stdin, and then copy it back when you want.

The dup() function duplicates an open file descriptor. Specifically, it provides an alternate interface to the service provided by the fcntl() function using the F_DUPFD constant command value, with 0 for its third argument. The duplicated file descriptor shares any locks with the original.

On success, dup() returns a new file descriptor that has the following in common with the original:

  • Same open file (or pipe)
  • Same file pointer (both file descriptors share one file pointer)
  • Same access mode (read, write, or read/write)
℡寂寞咖啡 2024-07-20 23:38:19
freopen("/my/newstdin", "r", stdin);
freopen("/my/newstdout", "w", stdout);
freopen("/my/newstderr", "w", stderr);

... do your stuff

freopen("/dev/stdin", "r", stdin);
...
...

这使得我的圆钉方孔测量仪上的指针达到了峰值,你想实现什么目的?

编辑:

请记住,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));

我相信这是 freopen() 的预期行为,正如您所看到的,您仍然只使用三个文件描述符(以及关联的流)。

这将覆盖任何 shell 重定向,因为 shell 不会重定向任何内容。 然而,它可能会破坏管道。 您可能需要确保为 SIGPIPE 设置一个处理程序,以防您的程序发现自己位于管道(不是 FIFO、管道)的阻塞端。

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

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

... do your stuff

freopen("/dev/stdin", "r", stdin);
...
...

This peaks the needle on my round-peg-square-hole-o-meter, what are you trying to accomplish?

Edit:

Remember that stdin, stdout and stderr are file descriptors 0, 1 and 2 for every newly created process. freopen() should keep the same fd's, just assign new streams to them.

So, a good way to ensure that this is actually doing what you want it to do would be:

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));

I believe this is the expected behavior of freopen(), as you can see, you're still only using three file descriptors (and associated streams).

This would override any shell redirection, as there would be nothing for the shell to redirect. However, its probably going to break pipes. You might want to be sure to set up a handler for SIGPIPE, in case your program finds itself on the blocking end of a pipe (not FIFO, pipe).

So, ./your_program --stdout /tmp/stdout.txt --stderr /tmp/stderr.txt should be easily accomplished with freopen() and keeping the same actual file descriptors. What I don't understand is why you'd need to put them back once changing them? Surely, if someone passed either option, they would want it to persist until the program terminated?

多孤肩上扛 2024-07-20 23:38:19

freopen 解决了简单的部分。 如果您没有读过任何内容并且愿意使用 POSIX 系统调用(例如 dupdup2),那么保留旧的标准输入并不难。 如果你开始阅读它,那么所有的赌注都将落空。

也许您可以告诉我们这个问题发生的背景?

我鼓励您坚持放弃旧的 stdinstdout 并因此可以使用 freopen 的情况。

freopen solves the easy part. Keeping old stdin around is not hard if you haven't read anything and if you're willing to use POSIX system calls like dup or dup2. If you're started to read from it, all bets are off.

Maybe you can tell us the context in which this problem occurs?

I'd encourage you to stick to situations where you're willing to abandon old stdin and stdout and can therefore use freopen.

木落 2024-07-20 23:38:19

与此同时,有一个 C 源代码库可以为您完成所有这些工作,重定向 stdout 或 stderr。 但最酷的部分是,它允许您为拦截的流分配任意数量的回调函数,从而使您可以非常轻松地将一条消息发送到多个目的地、数据库、文本文件等。

最重要的是,它使得创建外观和行为与 stdout 和 stderr 相同的新流变得微不足道,您也可以将这些新流重定向到多个位置。

在 *oogle 上查找 U-Streams C 库。

And in the meantime, there's a C source code library that will do all this for you, redirecting stdout or stderr. But the cool part is that it lets you assign as many callback functions as you want to the intercepted streams, allowing you then to very easily send a single message to multiple destinations, a DB, a text file, etc.

On top of that, it makes it trivial to create new streams that look and behave the same as stdout and stderr, where you can redirect these new streams to multiple locations as well.

look for U-Streams C library on *oogle.

半仙 2024-07-20 23:38:19

这是最容易获得、方便且有用的方法

freopen("dir","r",stdin);

This is the most readily available, handy and useful way to do

freopen("dir","r",stdin);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文