#c #linux
При чтении в программе на Си функцией fgets(str,sizeof(str),input) из сокета она может быть прервана сигналом в середине чтения строки. Часть строки уже занесена в str. Можно ли каким-либо способом (кроме самого примитивного - забить всю str перед чтением ньюлайнами) узнать сколько символов занесено в нее к моменту прерывания ? Может что-то полезное можно вытащить из struct _IO_FILE (из libio.h) ?
Ответы
Ответ 1
Вобщем-то - да, что-то полезное можно вытащить из _IO_FILE. Мне несколько раз этот вопрос попадался на глаза, но только сейчас я понял, что пару лет назад у меня был аналогичный вопрос: как определить, где остановился парсер после неудачного возврата из fscanf, чтобы правильно сдвинуть строковый буфер (сетевой пакет). Решение тогда пришло эмпирически: после очередного вызова fscanf я заглянул в структуру FILE и обнаружил, что _iobuf::_ptr как раз указывает на последний символ, который не соответствует шаблону. Для fgets, полагаю, это будет первый несчитанный из буфера символ. Если каждая строка файла не длиннее файлового буфера, то размер строки можно вычислить, посчитав разницу между "старым" и "новым" _iobuf::_ptr. Хотя вопрос с пометкой linux, обращаю внимание на характерные сходства в обеих структурах: в Windows: struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; и в Linux: struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ #define _IO_file_flags _flags /* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */ char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */ char *_IO_save_base; /* Pointer to start of non-current get area. */ char *_IO_backup_base; /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */ struct _IO_marker *_markers; struct _IO_FILE *_chain; int _fileno; #if 0 int _blksize; #else int _flags2; #endif _IO_off_t _old_offset; /* This used to be _offset but it's too small. */ #define __HAVE_COLUMN /* temporary */ /* 1+column number of pbase(); 0 is unknown. */ unsigned short _cur_column; signed char _vtable_offset; char _shortbuf[1]; /* char* _save_gptr; char* _save_egptr; */ _IO_lock_t *_lock; #ifdef _IO_USE_OLD_IO_FILE }; Скорее всего, Вас должен интересовать _IO_FILE::_IO_read_ptrОтвет 2
Открываем документацию на fgets (да, я знаю, cplusplus не очень достоверный источник, но все же) и читаем A terminating null character is automatically appended after the characters copied to str. То есть, сама функция добавляет нулевой символ. Поэтому, не нужно забивать нулями - ноль будет в конце строки. А дальше берем обычный strlen и смотрим длину. Это конечно не сильно эффективно, но работать точно будет. И самое главное - более-менее платформенно независимо.
Комментариев нет:
Отправить комментарий