Чому стандартний файл C ++ обробляє файл так, як це робиться?


17

C ++ використовує streamoffтип для відображення зміщення в потоці (файл) і визначається наступним чином у [stream.types]:

using streamoff = implementation-defined ;

Тип streamoff є синонімом одного з підписаних основних інтегральних типів достатнього розміру, щоб представити максимально можливий розмір файлу для операційної системи. 287)

287) Зазвичай довгий довгий.

Це має сенс, оскільки він дозволяє шукати у великих файлах (на відміну від використання long , який може бути лише 32 біта шириною).

[filebuf.virtuals] визначає basic_filebufфункцію пошуку у файлі наступним чином:

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

off_typeеквівалентно streamoff, див. [iostreams.limits.pos]. Однак стандарт продовжує пояснювати ефекти функції. Мене дратує саме останнє речення, яке вимагає дзвінка fseek:

Ефекти : Нехай widthпозначають a_codecvt.encoding(). Якщо is_open() == falseабо off != 0 && width <= 0, то операція позиціонування не вдасться. В іншому випадку, якщо way != basic_ios::curабо off != 0, і якщо була виведена остання операція, то оновіть послідовність виводу і запишіть будь-яку послідовність без змін. Далі, перейдіть до нової позиції: якщо width > 0, дзвоніть fseek(file, width * off, whence), інакше дзвоніть fseek(file, 0, whence).

fseekприймає longпараметр. Якщо off_typeі streamoffвизначено як long long(як це пропонує стандарт), це може призвести до переходу вниз longпри виклику fseek(file, width * off, whence)(що призводить до потенційно важкої діагностики помилок). Це ставить під сумнів ціле обгрунтування впровадження streamoffтипу.

Це навмисне чи дефект стандарту?


8
дефект виглядає так.
Якк - Адам Невраумон

Я думаю, я бачу, що gcc libstdc ++ використовує fseeko64 .
KamilCuk

1
З іншого боку, це не виглядає так, як seekoffобов'язково використовується fseek під кришкою. Швидше, поведінка (імовірно знайома?) fseekВикористовується для пояснення того, що seekoffробиться.
jjramsey

@jjramsey Це було і моє враження. Однак спосіб її фразування, швидше за все, пропонує швидше вимогу, а не пояснення.
jceed2

1
@jjramsey Я погоджуюся, що частина "Ефекти" може бути розумно інтерпретована таким чином, що вона насправді не повинна викликати fseek, поки вона робить щось з тим же ефектом. Але fseekзі зміщенням менше LONG_MINабо більше, ніж LONG_MAXце не має ефекту, тому пояснення в кращому випадку є неповним, принаймні для реалізацій, де streamoffширше, ніж long.
Кіт Томпсон

Відповіді:


6

Я думаю, що висновок, який ви робите з цього, про те, що між потоками C ++ є невідповідність і fseekщо призведе до помилок виконання, є невірним. Схоже, ситуація така:

  1. У системах, де long64 біт, streamoffвизначається як long, а seekoffфункція викликає fseek.

  2. У системах з long32-бітною версією, але ОС підтримує 64-розрядні зсуви файлів, streamoffвизначається як long longі seekoffвикликає функцію, що називається або, fseekoабо fseeko64приймає 64-бітове зміщення.

Ось фрагмент з визначення seekoffв моїй системі 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 розшифровується як підтримка великих файлів .

Висновок: Хоча стандарт пропонує визначення для streamoff яке нібито суперечить вимозі, яку seekoffвикликають fseek, дизайнери бібліотек розуміють, що вони повинні викликати варіант, fseekякий приймає весь спектр компенсацій, які підтримує ОС.


@ypnos Я не сказав, і вважаю цю відповідь корисною. Я здогадуюсь, що хтось прихилився, тому що він пропускає суть. Проблема не в тому, що існують здорові реалізації, які ігнорують стандарт в цьому плані, проблема полягає в тому, що стандарт повинен бути ігнорований, щоб реалізація була розумною.
jceed2

6
The situation seems to be:- Ситуація така , що реалізація не допускається не дзвонити fseekв seekoff. Він повинен дзвонити fseek, це не так, стандартний каже, що це потрібно. Я можу стверджувати, що ця реалізація недійсна. Я вважаю, що це не відповідає на питання. Ой, знайшли llvm , він дзвонить fseeko.
KamilCuk

Так само, як FYI, VC ++ вимагає _fseeki64цієї функції; що також, здається, порушує те, що говорить стандарт.
ChrisMM

1
Це справа тих, хто реалізує проблему та ігнорує стандарт. Я радий, що вони це зробили, але стандарт дійсно потрібно виправити.
NathanOliver

1
Деякі люди сприймають стандарт занадто буквально. Це не вимагає, щоб реалізація буквально викликала функцію, яка називається fseek. В іншому випадку стандарт описує щось як "начебто зателефонувавши fseek(...)". Якщо б так піклувалося про буквальне дзвінок fseek, це твердження було б інакше. Серйозно, що б ви зробили, якби впроваджували бібліотеку C ++? Чи наполягаєте ви на тому, щоб зателефонувати fseekза допомогою нижніх 32 біт зміщення 64-бітного файлу, тому що документ підказує вам? Чи подякували б ваші клієнти за це?
Вілліс Блекберн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.