Почему тип возвращаемого значения для ftell не fpos_t? - программирование

Почему тип возвращаемого значения для ftell не fpos_t?

Согласно C99, прототип для ftell является:

long int ftell(FILE *stream);

Из того, что я недооценил, должно быть следующее:

fpos_t ftell(FILE *stream);

Это почему?

Из §7.19.1-2

fpos_t который является типом объекта, отличным от типа массива, способного записывать всю информацию, необходимую для уникального указания каждой позиции в файле.

Я понимаю, что fpos_t должен использоваться для записи позиции в файле. Таким образом, ftell который возвращает позицию в файле, должен быть такого типа. Вместо этого это:

  • signed
  • типа long который может быть слишком маленьким или слишком большим для доступа к файлу на определенных архитектурах.
4b9b3361

Ответ 1

Обратите внимание, что fpos_t

[...] полный тип объекта, отличный от типа массива, способный записывать всю информацию, необходимую для уникального указания каждой позиции в файле.

Так что это может быть даже структура, совершенно непригодная для чего-либо еще, кроме вызова fsetpos !

С другой стороны, возвращаемое значение ftell является скаляром, который гарантированно можно будет использовать для определения точной позиции байта в двоичном файле:

Для двоичного потока значение представляет собой количество символов в начале файла.


Помимо этого, причина заключается в обратной совместимости. ftell он появился в C89, и, возможно, тогда ожидалось, что long будет масштабироваться достаточно быстро, чтобы вместить все размеры файлов, что не всегда верно в наши дни. К сожалению, невозможно изменить тип, возвращаемый ftell но уже слишком поздно менять это - даже те платформы, которые поддерживают большие файлы, теперь имеют функции с другим именем, такие как ftello.


подпись требуется, потому что функция возвращает -1 в случае ошибки.

Ответ 2

Из fgetpos()/fsetpos():

В некоторых не-UNIX-системах объект fpos_t может быть сложным объектом, и эти процедуры могут быть единственным способом переноса текстового потока с возможностью переноса.

тогда как ftell() требуется для возврата смещения указателя файла в файле. Это совершенно разные интерфейсы.

Ответ 3

Исторические причины.

fseek и ftell - очень старые функции, предшествующие стандартизации C. Они предполагают, что long достаточно велик, чтобы представлять позицию в любом файле - предположение, которое, вероятно, было справедливо в то время. long имеет размер не менее 32 бит, и, очевидно, у вас не может быть одного файла размером более 2 гигабайт (или даже 1,21 гигабайта).

К тому времени, когда был опубликован первый стандарт C (ANSI C, 1989), стало очевидно, что это предположение больше не действует, но изменение определений fseek и ftell нарушило бы существующий код. Более того, целочисленный тип по-прежнему не был шире, чем long (long long не был представлен до C99).

Комитет ANSI C решил, что fseek и ftell все еще полезны, но они представили новые функции позиционирования файлов fsetpos и fgetpos. Эти функции используют непрозрачный нечисловой тип fpos_t, а не long, что делает их более и менее гибкими, чем fseek и ftell. Реализация может определить fpos_t, чтобы она могла представлять любое возможное смещение файла - но, поскольку это не числовой тип, fsetpos и fgetpos не предоставляют функцию SEEK_SET/SEEK_CUR/SEEK_END, Например, нет способа использовать fsetpos для позиционирования файла до его конца.

Некоторые из них рассматриваются в Обосновании ANSI C, раздел 4.9.9:

Учитывая эти ограничения, Комитет по-прежнему считал, что эта функция [fseek] имеет достаточную полезность и используется в достаточном количестве существующего кода, чтобы гарантировать ее сохранение в Стандарте. fgetpos и fsetpos были добавлены для работы с файлами, которые слишком велики для обработки с fseek и ftell.

Если бы сегодня это определялось с нуля, вероятно, была бы одна пара функций, охватывающая все функции текущих четырех функций, вероятно, с использованием целочисленного типа typedef, который должен быть достаточно большим, чтобы представлять любое возможное смещение файла. (В современных системах 64-битных, вероятно, будет достаточно, но я не удивлюсь, если скоро увидим 8-эксабайтные файлы в больших системах).

Ответ 4

Наиболее вероятное использование этого - разрешить ошибочные возвращаемые значения в виде отрицательных чисел. Это то же самое, что и семейство функций printf, которые возвращают ssize_t вместо size_t, что является signed версией size_t.

Первый из этих трюков произошел с getchar(), который возвращает int вместо char, чтобы учесть значение, возвращаемое в конце условия файла (EOF), которое обычно является отрицательным значением по сравнению со всем набором возможных возвращаемых символов (в диапазоне от 0 до 255, все натуральные числа)

Почему не определить расширение со знаком того же типа для разрешения -1? На самом деле не знаю :)