Dlaczego standard C ++ obsługuje wyszukiwanie plików w taki sposób?

17

C ++ używa tego streamofftypu do reprezentowania przesunięcia w strumieniu (pliku) i jest zdefiniowany w następujący sposób w [stream.types]:

using streamoff = implementation-defined ;

Typ streamoff jest synonimem jednego z podpisanych podstawowych integralnych typów o wystarczającym rozmiarze, aby reprezentować maksymalny możliwy rozmiar pliku dla systemu operacyjnego. 287)

287) Zazwyczaj długi.

Ma to sens, ponieważ pozwala na wyszukiwanie w dużych plikach (w przeciwieństwie do używania long, które może mieć tylko 32 bity szerokości).

[filebuf.virtuals] definiuje basic_filebuffunkcję wyszukiwania w pliku w następujący sposób:

pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out) override;

off_typejest równoważne streamoff, patrz [iostreams.limits.pos]. Jednak standard wyjaśnia dalej efekty tej funkcji. Denerwuje mnie ostatnie zdanie, które wymaga połączenia z fseek:

Efekty : Niech widthoznacz a_codecvt.encoding(). Jeśli is_open() == falselub off != 0 && width <= 0, operacja pozycjonowania kończy się niepowodzeniem. W przeciwnym razie, jeśli way != basic_ios::curlub off != 0, i jeśli została wykonana ostatnia operacja, zaktualizuj sekwencję wyjściową i zapisz dowolną sekwencję cofania. Następnie szukaj nowej pozycji: jeśli width > 0zadzwoń fseek(file, width * off, whence), w przeciwnym razie zadzwoń fseek(file, 0, whence).

fseekakceptuje longparametr. Jeśli off_typei streamoffsą zdefiniowane jako long long(jak sugeruje standard), może to prowadzić do obniżenia konwersji do longpodczas wywoływania fseek(file, width * off, whence)(prowadząc do potencjalnie trudnych do zdiagnozowania błędów). To podważa całe uzasadnienie wprowadzenia tego streamofftypu w pierwszej kolejności.

Czy jest to celowe czy wada normy?

jceed2
źródło
8
wada wygląda.
Jak - Adam Nevraumont,
Myślę, że widzę, że gcc libstdc ++ używa fseeko64 .
KamilCuk,
1
Z drugiej strony nie wygląda to na seekoffkonieczność użycia fseek pod maską. Raczej (przypuszczalnie znajome?) Zachowanie fseeksłuży raczej do wyjaśnienia, co seekoffsię dzieje.
jjramsey
@jjramsey To też było moje wrażenie. Jednak sposób, w jaki jest wyrażony, wydaje się sugerować wymóg, a nie wyjaśnienie.
jceed2
1
@jjramsey Zgadzam się, że część „Efekty” można rozsądnie interpretować w ten sposób, że tak naprawdę nie musi ona wywoływać, fseeko ile robi coś z tym samym efektem. Ale fseekz przesunięciem mniejszym LONG_MINlub większym niż LONG_MAXnie ma żadnego efektu, więc wyjaśnienie jest w najlepszym razie niekompletne, przynajmniej w przypadku wdrożeń, które streamoffsą szersze niż long.
Keith Thompson

Odpowiedzi:

6

Myślę, że wniosek, z którego czerpiesz, że istnieje rozbieżność między strumieniami C ++ i fseekktóry doprowadzi do błędów w środowisku wykonawczym, jest błędny. Sytuacja wydaje się następująca:

  1. W systemach, w których longjest 64 bity, streamoffjest zdefiniowany jako longi seekofffunkcja jest wywoływana fseek.

  2. W systemach, gdzie longwynosi 32 bity, ale obsługuje 64-bitowe OS offsety w pliku, streamoffjest zdefiniowane jako long longi seekoffwywołuje funkcję o nazwie albo fseekoalbo fseeko64że akceptuje 64-bitowy offset.

Oto fragment kodu z definicji seekoffw moim systemie Linux:

#ifdef _GLIBCXX_USE_LFS
    if (!fseeko64(_M_file, __off, __whence))
      __ret = std::streampos(ftello64(_M_file));
#else
    if (!fseek(_M_file, __off, __whence))
      __ret = std::streampos(std::ftell(_M_file));
#endif

LFS oznacza obsługę dużych plików .

Wniosek: Chociaż standard sugeruje definicję streamofftego rzekomo sprzecznego z wymaganiem, które należy seekoffwywołać fseek, projektanci bibliotek rozumieją, że muszą nazwać wariant tego, fseekktóry akceptuje pełny zakres przesunięć obsługiwanych przez system operacyjny.

Willis Blackburn
źródło
@ypnos Nie oddałem głosu i uważam tę odpowiedź za przydatną. Wydaje mi się, że ktoś przegłosował, ponieważ nie ma sensu. Problemem nie jest to, że istnieją rozsądne implementacje, które ignorują standard w tym względzie, problem polega na tym, że standard należy zignorować, aby implementacja była rozsądna.
jceed2
6
The situation seems to be:- Sytuacja jest taka, że realizacja nie może nie wywołać fseekw seekoff. Musi zadzwonić fseek, nie ma, standard mówi, że musi. Mogę argumentować, że ta implementacja jest nieprawidłowa. Uważam, że to nie odpowiada na pytanie. Och, znalazłem lvvm , woła fseeko.
KamilCuk,
Podobnie jak FYI, VC ++ wywołuje _fseeki64tę funkcję; co również wydaje się naruszać to, co mówi standard.
ChrisMM,
1
Jest to przypadek, w którym realizatorzy zdają sobie sprawę z problemu i ignorują standard. Cieszę się, że tak, ale standard naprawdę musi zostać naprawiony.
NathanOliver,
1
Niektóre osoby zbyt dosłownie przyjmują ten standard. Nie jest wymagane, aby implementacja dosłownie wywoływała funkcję o nazwie fseek. Gdzie indziej standard opisuje coś jako „jakby przez telefon fseek(...)”. Gdyby tak bardzo mu zależało na dosłownym dzwonieniu fseek, to stwierdzenie byłoby inne. Poważnie, co byś zrobił, gdybyś implementował bibliotekę C ++? Czy nalegałbyś na wywołanie fseekprzy użyciu niższych 32 bitów 64-bitowego przesunięcia pliku, ponieważ dokument tak mówi? Czy Twoi klienci ci za to podziękują?
Willis Blackburn,