C语言 如何在 C 中关闭标准输出和标准错误?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4972994/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to close stdout and stderr in C?
提问by Usman
I need to close stdout and stderr for one of my C program. How is it possible without exiting the program in execution?
我需要为我的 C 程序之一关闭 stdout 和 stderr。怎么可能不退出正在执行的程序?
采纳答案by lhf
What have you tried? Doesn't fclosework?
你尝试过什么?不起作用fclose?
回答by
You can just:
你可以:
fclose(stdout);
fclose(stderr);
For anybody wondering why you might want to do this, this is a fairly common task for a daemon/service process on Unix.
对于想知道为什么要这样做的人来说,这是 Unix 上的守护程序/服务进程的一项相当常见的任务。
Howeveryou should be aware that closing a file descriptor may have unintended consequences:
但是,您应该意识到关闭文件描述符可能会产生意想不到的后果:
- When you open new files these now free descriptors will be used. So, for example, if you subsequently
fopenthat file descriptor (on Linux, at least) will replace fd 1, i.e. stdout. Any code that subsequently uses this will write to this file, which may not be what you intended. - See R..'s comments on file descriptors versus C library
FILE*pointers. Specifically:- If you write to a closed fd under Linux, you'll get an error, but:
- If you use a C library function that uses
stdoutorstderr(which areFILE*pointers (see their definition) then writing to these whilstFILE*is closed is undefined behaviour. This will likely crash your program in unexpected ways, not always at the point of the bug either. See undefined behaviour.
- Your code isn't the only part affected. Any libraries you use, and any processes you launch which inherited these file descriptors as their standard descriptors are also affected.
- 当您打开新文件时,将使用这些现在免费的描述符。因此,例如,如果您随后
fopen该文件描述符(至少在 Linux 上)将替换 fd 1,即 stdout。随后使用它的任何代码都将写入此文件,这可能不是您想要的。 - 请参阅 R.. 对文件描述符与 C 库
FILE*指针的评论。具体来说: - 您的代码不是唯一受影响的部分。您使用的任何库,以及您启动的任何继承这些文件描述符作为其标准描述符的进程也会受到影响。
The quick, one-line solution is to freopen()To say /dev/null, /dev/consoleunder Linux/OSX or nulon Windows. Alternatively, you can use your platform-specific implementation to re-open the file descriptors/handles as required.
快速的单行解决方案是freopen()说/dev/null,/dev/console在 Linux/OSX 或nulWindows 上。或者,您可以使用特定于平台的实现根据需要重新打开文件描述符/句柄。
回答by karlphillip
If you want to prevent your application from writing to the console, then:
如果您想阻止您的应用程序写入控制台,则:
#include <stdio.h>
int main()
{
fprintf(stdout, "stdout: msg1\n");
fprintf(stderr, "stderr: msg1\n");
fclose(stdout);
fprintf(stdout, "stdout: msg2\n"); // Please read the note setion below
fprintf(stderr, "stderr: msg2\n");
fclose(stderr);
fprintf(stdout, "stdout: msg3\n");
fprintf(stderr, "stderr: msg3\n");
}
Outputs:
输出:
stdout: msg1
stderr: msg1
stderr: msg2
Note:any attempt to use a FILE pointer after the file is closed is erroneous. I'm doing it in this case just to illustrate what closing these file descriptors mightdo to your application.
注意:在文件关闭后使用 FILE 指针的任何尝试都是错误的。在这种情况下,我这样做只是为了说明关闭这些文件描述符可能会对您的应用程序产生什么影响。
回答by FRIdSUN
Warning: I am not experienced in C at all, but recently read a slide that answers this question directly by Jim Meyering, a RedHat employee and GNUlib maintainer: https://www.gnu.org/ghm/2011/paris/slides/jim-meyering-goodbye-world.pdf. I merely summarize.
警告:我完全没有 C 方面的经验,但最近读了一张由 RedHat 员工和 GNUlib 维护者 Jim Meyering 直接回答这个问题的幻灯片:https://www.gnu.org/ghm/2011/paris/slides/ jim-meyering-goodbye-world.pdf。我只是总结一下。
TL;DR
TL; 博士
Get closeout.cand its dependencies from GNUlib into your source and call
将closeout.c及其依赖项从 GNUlib 获取到您的源代码中并调用
atexit(close_stdout);
as your first line in main.
作为你在 main 中的第一行。
Summary
概括
First, some heads up warning, quoting POSIX:
首先,一些注意警告,引用POSIX:
Since after the call to fclose() any use of stream results in undefined behavior, fclose() should not be used on stdin, stdout, or stderr except immediately before process termination, ...... If there are any atexit() handlers registered by the application, such a call to fclose() should not occur until the last handler is finishing. Once fclose() has been used to close stdin, stdout, or stderr, there is no standard way to reopen any of these streams.
Usage of close() on file descriptors STDIN_FILENO, STDOUT_FILENO or STDERR_FILENO should immediately be followed by an operation to reopen these file descriptors. ...... Furthermore, a close() followed by a reopen operation (e.g. open(), dup() etc) is not atomic; dup2() should be used to change standard file descriptors.
因为在调用 fclose() 之后,任何使用流都会导致未定义的行为,所以 fclose() 不应在 stdin、stdout 或 stderr 上使用,除非在进程终止之前,......如果有任何 atexit()应用程序注册的处理程序,在最后一个处理程序完成之前,不应发生对 fclose() 的此类调用。一旦使用 fclose() 关闭 stdin、stdout 或 stderr,就没有标准方法可以重新打开这些流中的任何一个。
对文件描述符 STDIN_FILENO、STDOUT_FILENO 或 STDERR_FILENO 使用 close() 后应立即执行重新打开这些文件描述符的操作。...... 此外,close() 之后是重新打开操作(例如 open()、dup() 等)不是原子的;dup2() 应该用于更改标准文件描述符。
Closing stream without handling its errors is not robust, and it is the same for stdout and stderr. Here is a list of errors you need to handle:
关闭流而不处理其错误是不可靠的,对于 stdout 和 stderr 也是如此。以下是您需要处理的错误列表:
fclose(stdout)ferror(stdout)a.k.a. previous error__fpending(stdout)a.k.a. stuff not flushed
fclose(stdout)ferror(stdout)又名以前的错误__fpending(stdout)又名东西没有冲洗
Handling these errors, as GNUlib implements in close-stream.c, is quoted below.
下面引用了GNUlib 在close-stream.c 中实现的这些错误的处理。
int
close_stream (FILE *stream)
{
const bool some_pending = (__fpending (stream) != 0);
const bool prev_fail = (ferror (stream) != 0);
const bool fclose_fail = (fclose (stream) != 0);
/* Return an error indication if there was a previous failure or if
fclose failed, with one exception: ignore an fclose failure if
there was no previous error, no data remains to be flushed, and
fclose failed with EBADF. That can happen when a program like cp
is invoked like this 'cp a b >&-' (i.e., with standard output
closed) and doesn't generate any output (hence no previous error
and nothing to be flushed). */
if (prev_fail || (fclose_fail && (some_pending || errno != EBADF)))
{
if (! fclose_fail)
errno = 0;
return EOF;
}
return 0;
}
Notice: __fpendingis special to glibc and may not be portable. OTOH, it is on the way to be standardizedas fpending.
注意:__fpending是 glibc 的特殊功能,可能不可移植。OTOH,它正在被标准化为fpending.
P.S.:
PS:
I just wanted to direct the stdout and stderr output to a log file instead of console.
我只是想将 stdout 和 stderr 输出定向到日志文件而不是控制台。
That is not a good reason to close stdout and stderr if you are writing a daemon according to http://cloud9.hedgee.com./scribbles/daemon#logging. You should let a daemon manager (such as daemon tools, runit, s6, nosh, OpenRC and systemd) handle the redirection.
如果您根据http://cloud9.hedgee.com./scribbles/daemon#logging编写守护程序,这不是关闭 stdout 和 stderr 的好理由。您应该让守护进程管理器(例如守护进程工具、runit、s6、nosh、OpenRC 和 systemd)处理重定向。
However, you still should close any stream that the program has ever written to in the end to check for errors. Quote from close-stream.c:
但是,您仍然应该关闭程序最后写入的任何流以检查错误。来自 close-stream.c 的报价:
If a program writes anythingto STREAM, that program should close STREAM and make sure that it succeeds before exiting. Otherwise, suppose that you go to the extreme of checking the return status of every function that does an explicit write to STREAM. The last printf can succeed in writing to the internal stream buffer, and yet the fclose(STREAM) could still fail (due e.g., to a disk full error) when it tries to write out that buffered data. Thus, you would be left with an incomplete output file and the offending program would exit successfully. Even calling fflush is not always sufficient, since some file systems (NFS and CODA) buffer written/flushed data until an actual close call.
Besides, it's wasteful to check the return value from every call that writes to STREAM -- just let the internal stream state record the failure. That's what the ferror test is checking below.
如果程序向 STREAM写入任何内容,该程序应关闭 STREAM 并确保它在退出之前成功。否则,假设您极端地检查对 STREAM 进行显式写入的每个函数的返回状态。最后一个 printf 可以成功写入内部流缓冲区,但是当 fclose(STREAM) 尝试写出缓冲数据时,它仍然可能失败(例如,由于磁盘已满错误)。因此,您将得到一个不完整的输出文件,并且有问题的程序将成功退出。即使调用 fflush 也并不总是足够的,因为一些文件系统(NFS 和 CODA)缓冲写入/刷新的数据,直到实际关闭调用。
此外,检查每个写入 STREAM 的调用的返回值是很浪费的——让内部流状态记录失败。这就是下面 ferror 测试要检查的内容。
回答by yangda
Actually you can also use the closefunction:
其实你也可以使用这个close函数:
#include<unistd.h> // close
#include<stdio.h> // STDOUT_FILENO,STDERR_FILENO
...
close(STDOUT_FILENO);
close(STDERR_FILENO);
...

