Input data: there is a kind of library that spits into stderr (stdout, not fundamentally) in case of errors. It would be desirable to save this business in the variables, but not to spoil the console. Especially since it may not be at all. And in general, I want to determine the time and location of the error message myself.

The simplest solution is to rediscover standard threads and setvbuf . Moreover, the authors of the library provide for their duplication initially. After that, everything becomes as if simple ( lib is a conditional structure containing data for the operation of this library):

 setvbuf( lib.StdOut, lib.OutBuf, _IOFBF, LIB_OUTBUF_SIZE ); /* ... много кода ... */ if( someLibFunction() == FIGNYA ) { handleExternalLibError( lib.OutBuf ); /* здесь сообщение об ошибке */ } 

The question is in the meaning of this very LIB_OUTBUF_SIZE . It was established experimentally (and with the flu from the library sources) that there could be a file name. One thing is important, and some texts. So, PATH_MAX+PATH_MAX to PATH_MAX+PATH_MAX for sure. And if there any .po -shipping, yes in German? Or what language is there with the longest expletives :)

In any case, I want some kind of universal approach. Ideas?

  • Not sure what the best solution is, but as an option, read the buffer in another thread at runtime someLibFunction() . - Vladimir Gamalyan
  • @VladimirGamalian Yeah, there were such ideas. But I would not like multithreading. From the word "absolutely" :) Not the case. - PinkTux
  • one
    Yes, and setvbuf will only set a buffer for the stream, but will it prevent output to the console? In addition, it You shouldn't try to access the values in the array directly while the stream is using it for buffering. those. It is not recommended to climb into the buffer. - Vladimir Gamalyan
  • @VladimirGamalian, there the threads are rediscovered, in this case at least in /dev/null , or NUL , it doesn't matter. The question is only in size. Enough to receive a message in the general case . - PinkTux
  • In fact, no one guarantees any particular way of using buffering. Yes, the buffer is allocated, but what is in it at any time - no one can guarantee you. So this way, to put it mildly, unreliable. Moreover, I do not exclude that, having found the redirection to nul , a sufficiently intelligent system will simply completely ignore the buffer ... :) - Harry

4 answers 4

The main point here is the unknown size of the message that comes from the library. Therefore, the use of static buffer is not desirable. But if it is possible to redirect flows. Why not redirect to pipe() . And then in the right place to take information from it.

  • Yes, this option was considered. But this is very confusing. Although, if you make a competent wrapper ... Eh, lazy people - programmers :) - PinkTux

There is a kind of library that spits into stderr (stdout, not fundamentally) in case of errors. It would be desirable to save this business in the variables, but not to spoil the console. Especially since it may not be at all.

You can redirect the output to a file using the freopen() function :

 #include <stdio.h> #include <stdlib.h> int main(void) { puts("stdout is printed to console"); if (freopen("redir.txt", "w", stdout) == NULL) { perror("freopen() failed"); return EXIT_FAILURE; } puts("stdout is redirected to a file"); // this is written to redir.txt fclose(stdout); } 

See Rerouting stdin and stdout from C. On POSIX, freopen() can be implemented using dup2() (redirection at the file descriptor level) , example code .

It is worth mentioning that stdout NOT guaranteed to be an lvalue, so do not write: stdout = ...


setvbuf() has nothing to do with stdout / stderr interception in C. setvbuf() simply changes the buffering mode for a given FILE* stream:

It is an undetermined behavior.

This quote from the setvbuf() documentation says that using OutBuf after a successful call to setvbuf() is UB (for example, the standard allows you to launch a rocket to Mars, encrypt a hard disk and not give a key until the concept "undefined behavior" and why avoid firmly in your head will not be postponed).

The last argument to setvbuf() is of type size_t , so LIB_OUTBUF_SIZE is not a file name - in the sense it is just the size of the OutBuf buffer. PATH_MAX ( "max. Path length" ) is also not related to the interception of stdout / stderr in C in any way.

If the library explicitly provides the StdOut variable, then read its documentation how to recommend this variable, for example:

 StdOut = fmemopen(your_buffer, sizeof your_buffer, "w"); 

fmemopen () assumes that your library will never write more than the sizeof your_buffer bytes in the StdOut stream.

    As pointed out in the comments, you can create your buffer and write to it: an example . It uses open_memstream from the POSIX 2008 standard. For platforms without its support, there are ports and similar functions. For example, for BSD and Mac OS, iOS and Windows . That's all, two hares are caught: the problem is solved, you don’t need to dig into the topic too much :)

    • I myself am a fan of the approach "let the mast give", but if it is not going from native sources in the studio in 2015 without the "support" - sorry. - PinkTux

    In my opinion, a 100% reliable solution is to use inotify, I just don’t know if it will work for a species carrier ... Namely:

    1) Run your program (for example, test) with the redirection of stdout / stderr to the file:

     # test > err_msg.txt 2>&1 

    2) Inside the main function, we initialize the inotify system:

     #include <sys/inotify.h> ... int main() { ... int fd, wd; fd = inotify_init(); 

    3) We inform the OS that we want to monitor the recording in the err_msg.txt file

     wd = inotify_add_watch( fd, "err_msg.txt", IN_MODIFY ); 

    4) And then there are two options:

    4.1) You try to read the inottify pseudo-file after each function call from the library (non-blocking reading) 4.2) You organize a separate thread to read this file.

    5) By anyone if reading

     length = read( fd, buffer, BUF_LEN ); if ( length < 0 ) { perror( "read" ); } 

    worked, then it only means one thing - the err_msg.txt file has been modified and you need to look at it. To analyze the buffer, in order to find out what kind of event occurred it makes no sense - you requested monitoring of ONE event only.

    Well, then - according to circumstances ... :-)