fflush(stdout) in c

纵然是瞬间 提交于 2019-12-01 11:05:15

You almost certainly can, but you probably shouldn't. The standard requires only that FILE be a type that is useful to the implementation to identify an open file and whatever state is required to implement the semantics of the various functions that operate on streams.

I'd generally agree with other posters that fflush() is a reliable way to know what you actually wrote to the file.

However, if you have lost track of what parts of your code might be writing to a stream, then it can occasionally be useful to watch the stream in action and catch it changing.

In practice, FILE is a typedef for a struct that is declared by your implementation in the header file stdio.h (often named struct _iobuf). Although a typical implementation only lightly documents its members, a typical implementation also implements putchar() and some of its friends as macros that are also found in stdio.h. That, combined with the likely availability of sources for the C runtime library of any toolchain you are likely to be using with gdb, gets you all the information you need to peek under the hood.

The stdio.h provided in MinGW GCC 3.4.5 implements FILE as follows:

typedef struct _iobuf
{
    char*   _ptr;
    int _cnt;
    char*   _base;
    int _flag;
    int _file;
    int _charbuf;
    int _bufsiz;
    char*   _tmpfname;
} FILE;

// oversimplify declaration of _iob[] here for clarity:
extern FILE _iob[FOPEN_MAX];    /* An array of FILE imported from DLL. */
//...
#define STDIN_FILENO    0
#define STDOUT_FILENO   1
#define STDERR_FILENO   2
#define stdin   (&_iob[STDIN_FILENO])
#define stdout  (&_iob[STDOUT_FILENO])
#define stderr  (&_iob[STDERR_FILENO])

and implements putchar() as an inline function taking advantage of a GCC extension to C:

__CRT_INLINE int __cdecl __MINGW_NOTHROW putchar(int __c)
{
  return (--stdout->_cnt >= 0)
    ?  (int) (unsigned char) (*stdout->_ptr++ = (char)__c)
    :  _flsbuf (__c, stdout);}

From this you can tell that the end of the buffer is pointed to by the member _ptr, and infer that the only other char * in struct _iobuf (_base) is pointing to the beginning of the buffer. The member _cnt is clearly the count of unused characters remaining in the buffer. The function _flsbuf() must take the first character that didn't fit and put it at the beginning of the buffer after it wrote the current buffer content to the file and restored the _cnt field.

So, if you watch stdout->_base and BUFSIZ - stdout->_cnt you would, for this implementation, have a display of how much and what is in the current buffer.

If you allocate a buffer yourself and pass it to setvbuf, I suppose you can access it before a flush, since it's yours to begin with.

EDIT: Your comment made your intent more clear, but what you want won't be easy:

  1. Set up your own buffer as described above,
  2. Set a read watchpoint on stdout,
  3. Watch your program slow to a crawl.

From then on, gdb will break each time anything accesses stdout, and you can check your buffer for changes, weird output, etc.

That said, that's not an ideal solution at all. A far better approach would be using a logging-enabled output function everywhere in your code.

I think it is better to flush stdout, which means basically you are seeing the content on the screen or in a file(if stdout is redirected).

use "setbuf()", and keep a handle to the buffer, which you can peek at. Unfortunately, I don't know off the top how to find the offset and length of unflushed data.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!