Флеш (стандартный) в с
В тот момент, когда я нахожусь на fflush(stdout) и перерываюсь туда в GDB, могу ли я узнать, что находится в stdout, прежде чем я его на самом деле напечатаю?
Как я могу узнать, что есть в stdout в любой момент времени?
4 ответа
Вы почти наверняка можете, но, вероятно, не должны. Стандарт требует только того, чтобы FILE
быть типом, который полезен для реализации для идентификации открытого файла и любого состояния, необходимого для реализации семантики различных функций, работающих с потоками.
Я бы в целом согласился с другими fflush()
надежный способ узнать, что вы на самом деле написали в файл.
Однако, если вы потеряли отслеживание того, какие части вашего кода могут записывать в поток, иногда полезно наблюдать за потоком в действии и отслеживать его изменение.
На практике, FILE
является typedef для struct
который объявлен вашей реализацией в заголовочном файле stdio.h (часто называется struct _iobuf
). Хотя типичная реализация лишь слегка документирует своих членов, типичная реализация также реализует putchar()
и некоторые из его друзей в качестве макросов, которые также находятся в stdio.h. Это, в сочетании с вероятной доступностью источников для библиотеки времени выполнения C любой цепочки инструментов, которую вы, вероятно, будете использовать с gdb, дает вам всю необходимую информацию, чтобы заглянуть под капот.
Stdio.h, предоставляемый в MinGW GCC 3.4.5, реализует FILE
следующее:
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])
и реализует putchar()
как встроенная функция, использующая расширение GCC до C:
__CRT_INLINE int __cdecl __MINGW_NOTHROW putchar(int __c)
{
return (--stdout->_cnt >= 0)
? (int) (unsigned char) (*stdout->_ptr++ = (char)__c)
: _flsbuf (__c, stdout);}
Из этого вы можете сказать, что конец буфера указывает член _ptr
и сделать вывод, что единственный другой char *
в struct _iobuf
(_base
) указывает на начало буфера. Член _cnt
явно количество неиспользованных символов, оставшихся в буфере. Функция _flsbuf()
должен взять первый неподходящий символ и поместить его в начало буфера после того, как он записал текущее содержимое буфера в файл и восстановил _cnt
поле.
Итак, если вы смотрите stdout->_base
а также BUFSIZ - stdout->_cnt
для этой реализации у вас будет отображение того, сколько и что находится в текущем буфере.
Если вы выделите буфер самостоятельно и передадите его в setvbuf, я полагаю, что вы можете получить к нему доступ до сброса, поскольку он ваш с самого начала.
РЕДАКТИРОВАТЬ: Ваш комментарий сделал ваши намерения более ясными, но то, что вы хотите, не будет легко:
- Настройте свой собственный буфер, как описано выше,
- Установить точку наблюдения чтения
stdout
, - Смотреть вашу программу медленно, чтобы ползти.
С тех пор, gdb
будет каждый раз ломаться stdout
и вы можете проверить свой буфер на наличие изменений, странных выводов и т. д.
Тем не менее, это не идеальное решение вообще. Гораздо лучшим подходом было бы использование функции вывода с поддержкой ведения журнала везде в вашем коде.
Я думаю, что лучше смывать stdout
, что означает, что в основном вы видите содержимое на экране или в файле (если stdout
перенаправлен).
Используйте "setbuf()" и держите дескриптор буфера, который вы можете посмотреть. К сожалению, я не знаю, как найти смещение и длину непроверенных данных.