Флеш (стандартный) в с

В тот момент, когда я нахожусь на 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, я полагаю, что вы можете получить к нему доступ до сброса, поскольку он ваш с самого начала.

РЕДАКТИРОВАТЬ: Ваш комментарий сделал ваши намерения более ясными, но то, что вы хотите, не будет легко:

  1. Настройте свой собственный буфер, как описано выше,
  2. Установить точку наблюдения чтения stdout,
  3. Смотреть вашу программу медленно, чтобы ползти.

С тех пор, gdb будет каждый раз ломаться stdout и вы можете проверить свой буфер на наличие изменений, странных выводов и т. д.

Тем не менее, это не идеальное решение вообще. Гораздо лучшим подходом было бы использование функции вывода с поддержкой ведения журнала везде в вашем коде.

Я думаю, что лучше смывать stdout, что означает, что в основном вы видите содержимое на экране или в файле (если stdout перенаправлен).

Используйте "setbuf()" и держите дескриптор буфера, который вы можете посмотреть. К сожалению, я не знаю, как найти смещение и длину непроверенных данных.

Другие вопросы по тегам