2

What is a C equivalent to this C++ answer for temporarily silencing output to cout/cerr and then restoring it?

How to silence and restore stderr/stdout?

(Need this to silence noise from 3rd party library that I am calling, and to restore after the call.)

user2052436
  • 4,321
  • 1
  • 25
  • 46

2 Answers2

3

This is a terrible hack, but should work:

#include <stdio.h>
#include <unistd.h>


int
suppress_stdout(void)
{
    fflush(stdout);
    int fd = dup(STDOUT_FILENO);
    freopen("/dev/null", "w", stdout);
    return fd;
}

void
restore_stdout(int fd)
{
    fflush(stdout);
    dup2(fd, fileno(stdout));
    close(fd);
}

int
main(void)
{
    puts("visible");
    int fd = suppress_stdout();
    puts("this is hidden");
    restore_stdout(fd);
    puts("visible");
}
William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • why it's a hack? Ithink it's confirming to POSIX spec.. question what to do on a non-POSIX system. – Swift - Friday Pie Dec 15 '21 at 23:17
  • 3
    Minor nitpick: Shouldn't it be `close(fd);` last in `restore_stdout`? I made a version of this that works on Posix and Windows [here](https://godbolt.org/z/zWo1vdTvc) - but for some reason it doesn't actually work on Godbolt... – Ted Lyngmo Dec 15 '21 at 23:32
  • Why `STDOUT_FILENO` in `suppress_stdout` while `fileno(stdout)` in `restore_stdout`? – user2052436 Dec 16 '21 at 02:49
  • 1
    @user2052436 No particular reason. I believe either is correct, but there may be pedagogical reasons to prefer one over the other, so I thought I'd demonstrate both. – William Pursell Dec 16 '21 at 13:25
  • 1
    @TedLyngmo Excellent suggestion. Will edit. – William Pursell Dec 16 '21 at 13:26
  • @Swift I call it a "hack" because manipulating the underlying file descriptors of any FILE * feels dirty. I would hate to see this code in production, and would heartily curse its author. – William Pursell Dec 16 '21 at 13:28
  • afaik it happen anyway in various daemons and shell-like programs. As well as magic that hsppens when the program uses fork(). Alot of this information now slips under the hood of frameworks... until programmer runs into an issue where a spawned subprocess had hijacjed a file or socket or closed a stream. If anything, we have to curse Unix DNA. – Swift - Friday Pie Dec 16 '21 at 19:19
  • 1
    @TedLyngmo because permission was denied to open "/dev/null". I added error handling and `perror()` calls to track it (which one always should do). First part works, but stdout forever becomes invalid. Not sure how program can fix that either, because required `freopen ("/dev/stdout", "a", stdout);` also fails - only read the permission exists. I guess their busybox or whatever they use doesn't support that, the trick works in other environments: wandbox, onlinegdb. – Swift - Friday Pie Dec 17 '21 at 07:51
  • @Swift-FridayPie Aha, that makes sense. – Ted Lyngmo Dec 17 '21 at 08:06
  • @TedLyngmo I tried your version, "visible 1" is printed normally but "visible 2" is not printed. – Zehui Lin Jul 31 '23 at 06:45
  • @ZehuiLin What compiler and what target OS are you using? I tested it on a Linux and a Windows machine. – Ted Lyngmo Jul 31 '23 at 06:59
  • @TedLyngmo "visible 2" was not printed on the page you provided. Then I compiled the codes on [ideone](https://ideone.com) and "visible 2" was still not printed. Finanly I tries the codes on my PC locally and they works well. There must be something special happening on online IDEs... – Zehui Lin Jul 31 '23 at 07:22
  • @ZehuiLin Yes. I mentioned that in the comment as well. It's hard to debug that issue but it works in normal settings. – Ted Lyngmo Jul 31 '23 at 07:25
1
#include <stdio.h>

#ifdef _WIN32
#define NULL_DEVICE "NUL:"
#define TTY_DEVICE "COM1:"
#else
#define NULL_DEVICE "/dev/null"
#define TTY_DEVICE "/dev/tty"
#endif

int main() {
    printf("hello!\n");

    freopen(NULL_DEVICE, "w", stdout);
    freopen(NULL_DEVICE, "w", stderr);

    printf("you CAN'T see this stdout\n");
    fprintf(stderr, "you CAN'T see this stderr\n");

    freopen(TTY_DEVICE, "w", stdout);
    freopen(TTY_DEVICE, "w", stderr);

    printf("you CAN see this stdout\n");
    fprintf(stderr, "you CAN see this stderr\n");
    return 0;
}
codyne
  • 552
  • 1
  • 9