I actually have a solution to this problem, but I'm wondering if there is a slicker one.
I have the need to load in a library to my utility using dlopen
and then call one of the functions.
Unfortunately, the function spews a whole bunch of information out onto STDOUT and this I do not want.
I have a solution that is non-portable and I'm wondering if there's a better, more generic solution that I could use.
Here's what I have (NB: This 开发者_开发百科is C) :
/*
* Structure for retaining information about a stream, sufficient to
* recreate that stream later on
*/
struct stream_info {
int fd;
fpos_t pos;
};
#define STDOUT_INFO 0
#define STDERR_INFO 1
struct stream_info s_info[2];
point_stream_to_null(stdout, &s_info[STDOUT_INFO]);
point_stream_to_null(stderr, &s_info[STDERR_INFO]);
void *output = noisy_function();
reset_stream(stderr, &s_info[STDERR_INFO]);
reset_stream(stdout, &s_info[STDOUT_INFO]);
/*
* Redirects a stream to null and retains sufficient information to restore the stream to its original location
*** NB ***
* Not Portable
*/
void point_stream_to_null(FILE *stream, struct stream_info *info) {
fflush(stream);
fgetpos(stream, &(info->pos));
info->fd = dup(fileno(stream));
freopen("/dev/null", "w", stream);
}
/*
* Resets a stream to its original location using the info provided
*/
void reset_stream(FILE *stream, struct stream_info *info) {
fflush(stream);
dup2(info->fd, fileno(stream));
close(info->fd);
clearerr(stream);
fsetpos(stream, &(info->pos));
}
Any suggestions?
I have a suggestion, which lets you use the preprocessor for portability, or perhaps "portability".
If you try something like
#if defined __unix__
#define DEVNULL "/dev/null"
#elif defined _WIN32
#define DEVNULL "nul"
#endif
(ignoring other OSes, else case, error directive, etc.) and then reopen the file as before
FILE *myfile = freopen(DEVNULL, "w", stream);
then that may give you what you want.
I haven't tried this at home, though. The "nul" file exists; see /dev/null in Windows. And you can get predefined macros at "Pre-defined C/C++ Compiler Macros".
You could try using setvbuf
to set stdout
to have a very large buffer and be fully buffered. Then, after every call to noisy_function
, clear out the buffer before flushing it to the stream. I think this invokes undefined behavior though.
Another way would be to redirect stdout to a temp file, like with this macro function.
#include <stdio.h>
#define QUIET_CALL(noisy) { \
FILE* tmp = stdout;\
stdout = tmpfile();\
(noisy);\
fclose(stdout);\
stdout = tmp;\
}
int main(){
QUIET_CALL(printf("blah blah"));
printf("bloo bloo\n");
return 0;
}
For Windows console applications:
freopen("NUL", "w", stdout); // redirect stdout to the windows version of /dev/null
NoisyDllFunction();
freopen("CON", "w", stdout); // redirect stdout back to the console
Worked for me.
In Windows you can redirect streams too. See http://support.microsoft.com/kb/110930/en-us
Unfortunately, freopening to a platform-specific null filename is about the closest you can get in standard C. You could also consider modifying the library itself to not spew so much output on stdout.
That said, in practice, the only OSes you need to worry about are either unix-based (including MacOS) or Windows - in the case of Windows, stdout is hidden by default, so you can just skip the redirection step, and for *nix you have the code already.
精彩评论