crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

3 страниц V   1 2 3 >  
Ответить в данную темуНачать новую тему
> Фича в стандартной библиотеке С++, ifstream::seekg иногда не работает
Iron Bug
  опции профиля:
сообщение 5.10.2012, 14:46
Сообщение #1


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


В общем, напоролась я на фичу (как оказалось, а не багу), потратила кучу времени. Хочу предупредить всех, что она есть.
Проблема в том, что в стандартном ifstream, после чтения до конца файла (eof()), функция seekg работать перестаёт.
Вот простой код, который даёт неравные буферы:

// TestIfstreamSeekg.cpp 

#include <fstream>
#include <iostream>

using namespace std;

#define BUFFER_SIZE 10

int main(int argc, char* argv[])
{
    ifstream ifs("TestIfStreamSeekg.exe",ios::binary); // любой файл, длиной больше 10 байт, для простоты взят сам exe-шник, формат открытия неважен, может быть и текстовый

    // читаем первые байты
    char buffer0[BUFFER_SIZE];
    ifs.read(buffer0,BUFFER_SIZE);

    // доходим до eof()
    char temp[1000];
    while(!ifs.eof())
    {
        ifs.read(temp,1000);
    }
      
    //ifs.clear(); // а это волшебный финт ушами, который при раскомментировании помогает заставить seekg работать (шаманство подсмотрено на других форумах)
    // перемещаемся к началу файла (якобы)
    ifs.seekg(0,ios::beg);

    // снова читаем первые байты
    char buffer1[BUFFER_SIZE];
    ifs.read(buffer1,BUFFER_SIZE);
  
    // сравниваем считанные буферы
    if(memcmp(buffer0,buffer1,BUFFER_SIZE) != 0)
    {
        // опа! буферы разные
        cout << "buffers are not equal!" << endl;
    }
    else
    {
        // всё зашибись!
        cout << "buffers are equal" << endl;
    }
    ifs.close();
    return 0;
}


решение проблемы - сброс бита: перед вызовом seekg() вызывать clear(). можно ещё переоткрыть файл - тоже, естественно, сработает.
главное, знать об этом косяке :)

Сообщение отредактировал Iron Bug - 5.10.2012, 15:46
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ssoft
  опции профиля:
сообщение 5.10.2012, 15:21
Сообщение #2


Участник
**

Группа: Участник
Сообщений: 130
Регистрация: 17.2.2010
Из: Москва
Пользователь №: 1470

Спасибо сказали: 30 раз(а)




Репутация:   3  


Дак вроде так везде работает, не только под MSVS.

При достижении конца выставляется статус eofbit (тип iostate), аля кутешного ReadPastEnd.
Пока статус не изменится с помощью clear() на goodbit (в Qt resetStatus() изменяет на Ok) ничего с потоком сделать нельзя, в том числе и вернуться в начало.

Сообщение отредактировал ssoft - 5.10.2012, 15:34
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 5.10.2012, 15:44
Сообщение #3


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


Цитата(ssoft @ 5.10.2012, 18:21) *
Дак вроде так везде работает, не только под MSVS.

При достижении конца выставляется статус eofbit (тип iostate), аля кутешного ReadPastEnd.
Пока статус не изменится с помощью clear() на goodbit (в Qt resetStatus() изменяет на Ok) ничего с потоком сделать нельзя, в том числе и вернуться в начало.

действительно. я дома под линём проверила только что.
значит, просто я столько лет не знала о такой странной фиче. видимо, никогда не пыталась перемещаться по файлу после прочтения его до конца, а тут понадобилось.
и всё же, почему eof считается "ошибкой" - мне непонятно. обычный статус потока, почему его нужно обрабатывать как-то отдельно - полная загадка.

ладно, переименую тему, чтобы было более адекватно.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 7.10.2012, 14:05
Сообщение #4


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Да бага это однозначно, просто авторы отмазываются.

Если некая функция позволяет устанавливать указатель куда-нибудь, значит он должен безоговорочно устанавливаться.

Единственное место в котором бессмысленна установка указателя - последовательные интерфейсы.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 8.10.2012, 9:08
Сообщение #5


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


Цитата(Litkevich Yuriy @ 7.10.2012, 17:05) *
Да бага это однозначно, просто авторы отмазываются.

Если некая функция позволяет устанавливать указатель куда-нибудь, значит он должен безоговорочно устанавливаться.

Единственное место в котором бессмысленна установка указателя - последовательные интерфейсы.

ну вот как бы и я так же думала: раз это файл, то ползать по нему можно туда-сюда без ограничений. а оказалось, что eof его переводит в какое-то особое невменяемое состояние и надо ещё отслеживать, был ли этот eof. с моей точки зрения, это маразм, конечно. если я на начало файла перевожу указатель чтения, то какая мне разница, был он в конце или в середине... тем не менее, вот так вот реализовано. причём везде.

Сообщение отредактировал Iron Bug - 8.10.2012, 9:09
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Влад
  опции профиля:
сообщение 8.10.2012, 15:49
Сообщение #6


Участник
**

Группа: Участник
Сообщений: 146
Регистрация: 20.3.2009
Из: Санкт-Петербург
Пользователь №: 627

Спасибо сказали: 46 раз(а)




Репутация:   8  


Это не отмазка, а точное следование требованию Стандарта языка.
Бит eofbit устанавливается в момент попытки чтения за концом файла - естественно, попытка эта неудачная; и поэтому одновременно устанавливается failbit. В соответствии с буквой Стандарта (27.7.2.3, cl.41,43), операция seekg() игнорируется до тех пор, пока не будет сброшен failbit.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 9.10.2012, 20:21
Сообщение #7


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


просто стандарт слишком древний. он не соответствует нормальной логике потоков со свободным доступом :) это типичный лишний вызов. если я хочу переместиться а абсолютный старт потока со свободным доступом - это всегда возможно, где бы ни находился указатель. возможно, стандарт писали, когда файлы хранились на каких-нибудь первобытных устройствах типа лент.
в общем, проще написать обёртку, которая перегружает это дело, проверяет и сбрасывает этот никому не нужный бит, юзать её и не париться.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Влад
  опции профиля:
сообщение 9.10.2012, 21:01
Сообщение #8


Участник
**

Группа: Участник
Сообщений: 146
Регистрация: 20.3.2009
Из: Санкт-Петербург
Пользователь №: 627

Спасибо сказали: 46 раз(а)




Репутация:   8  


Хмм... Называть 14882-2011 "слишком древним" я бы, пожалуй, не стал бы... :-)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 10.10.2012, 6:55
Сообщение #9


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


Цитата(Влад @ 10.10.2012, 0:01) *
Хмм... Называть 14882-2011 "слишком древним" я бы, пожалуй, не стал бы... :-)

дык, это ж не в новом варианте появилось. это рудимент от старых времён остался. просто забыли пересмотреть.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Влад
  опции профиля:
сообщение 10.10.2012, 9:41
Сообщение #10


Участник
**

Группа: Участник
Сообщений: 146
Регистрация: 20.3.2009
Из: Санкт-Петербург
Пользователь №: 627

Спасибо сказали: 46 раз(а)




Репутация:   8  


Может, забыли, а может - нет.... Мы не знаем всех соображений, которыми руководствовался Комитет (а работают там отнюдь не глупые люди).
Я бы предложил тебе написать письмо с обоснованием в WG21 - они довольно объективно принимают предложения по совершенствованию Стандарта. Я допускаю, что были какие-то основания написать в Стандарте именно так, а не иначе, - какие именно, будет ясно из ответного письма. Из известных мне случаев (писал предложения не я), ответ приходит всегда, - даже если это вежливый отказ. По крайней мере, если твое предложение не будет принято, мы через пару месяцев будем четко знать, почему Стандарт требует делать так, а не иначе.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

3 страниц V   1 2 3 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 29.3.2024, 9:21