Writing to two file descriptors by only one operat

2019-09-14 17:06发布

I want to implement logging functionality in C and log messages to both stdout and some file. I would like to write something like fprintf(logout, "msg"); with somehow declared FILE* logout which will redirect strings to both stdout and some file. Is it possible?

3条回答
老娘就宠你
2楼-- · 2019-09-14 17:15

You apparently want a FILE-like object that redirects its writes to two underlying FILEs (stdout and the log file). Standard C doesn't allow "subclassing" FILE objects in any way, so this is not possible in C. However, GNU libc does, so if your program is Linux-only, you can do that with some programming. As this is extremely non-portable, it is strongly recommended against.

A more portable way to achieve this is by writing to a pipe and creating a process or thread that reads from the pipe and writes to both underlying files. For example, assuming POSIX:

FILE *tee_file(FILE *fp1, FILE *fp2)
{
  int fds[2];
  if (pipe(fds))
    return NULL;
  switch (fork()) {
    case 0: {
      char buf[512];
      int nread;
      FILE *r = fdopen(fds[0], "r");
      close(fds[1]);
      while ((nread = fread(buf, 1, sizeof buf, r)) {
        fwrite(buf, 1, nread, fp1);
        fwrite(buf, 1, nread, fp2);
      }
      _exit(0);
    }
    case -1:
      return NULL;
  }
  close(fds[0]);
  return fdopen(fds[1], "w");
}

/* after calling "fp = tee_file(fp1, fp2)", writes to fp
   end up in fp1 and fp2. */

Both approach add a good deal of complication to your program which should be justified by a very good reason. What you want is to use a logging framework that allows writing to multiple outputs (they all do), or write your own as outlined by H2CO3's answer.

查看更多
Melony?
3楼-- · 2019-09-14 17:23

Why don't you make your very own logging function?

int log_fprintf(FILE *stream, const char *restrict fmt, ...)
{
    va_list args;

    va_start(args, fmt);
    vfprintf(stream, fmt, args);
    va_end(args);

    va_start(args, fmt);
    int n = vfprintf(stdout, fmt, args);
    // conceptually, rather `stderr`, please!
    va_end(args);

    return n;
}
查看更多
祖国的老花朵
4楼-- · 2019-09-14 17:31

If this is on Linux, you can open a pipe to the tee command:

FILE *logout = popen("tee logfile", "w");
查看更多
登录 后发表回答