Флейм
GameDev.ru / Флейм / Форум / Норкомания stdio.h

Норкомания stdio.h

Страницы: 1 2 3 Следующая »
Panzerschrek[CN]Участникwww13 окт. 20187:24#0
Рассмотрим интерфейс по работе с файлами в Сишке.

Открытие файла:

FILE * fopen ( const char * filename, const char * mode );
почему mode - строка? Почему не флаги? Как могли додуматься до такого подхода? С флагами работать понятно как, но строку надо ведь парсить.


Чтение из файла и запись в файл:

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
Зачем тут size и count?  Пользователь сам не может перемножить? Для какого-нибудь malloc руками ведь надо умножать.


Далее, присмотрися к функции перемотки:

int fseek ( FILE * stream, long int offset, int origin );
Тут вроде-бы всё хорошо, последний аргумент - флаг, а не строка, как в fopen.
Но почему в этой функции файл передаётся первым аргументом, а во всяких fread, fwrite - последним? Какая-то неконсистентность.


Есть у нас также странности с набором функций:

int putc ( int character, FILE * stream );
int fputc ( int character, FILE * stream );
Функции эквивалентны. Нафига надо иметь два имени для одной и той же функции?
Есть ещё третья функция:
int putchar ( int character );
Но, хоть putchar похоже на putc, смысл у них разный - putchar пишет в стандартный вывод, а не в заданный файл.


Глядя на всё вышеизложенное, хочется спросить - что употребляли создатели всего этого? Как Международная Организация Стандартизации позволила оформить весь этот бред как стандарт?

Правка: 13 окт. 2018 7:25

skalogryzУчастникwww13 окт. 20188:03#1
для структурных языков низлежайшее API может быть сколь угодно убогим.
ведь всегда можно написать православную обёртку.

Panzerschrek[CN]
> Как Международная Организация Стандартизации позволила оформить весь этот бред
> как стандарт?
ИСО много всякого бреда (те же Кресты!) приняло как стандарт.
Они не являются организацией оценивающее качество, они просто принимают предложения на которые согласны, более менее все участники индустрии.
Оформляют и оглашают. Всё. И уж тем более они не следят затем за соблюдением стандарта. Этим занимаются сами участники индустрии (обвиняя друг друга в несоблюдении) 

Panzerschrek[CN]
> почему mode - строка? Почему не флаги? Как могли додуматься до такого подхода?
Расширяемость. Флагов на всех ненапосёшься и непредусмотришь. (для сравнения в винде 4 набора флагов, по факту хватит и одного)
"парсинг" по времени занимает ничтожную часть времени, открытия файла.

Panzerschrek[CN]
> Зачем тут size и count?  Пользователь сам не может перемножить?
может быть упиралось что работают читают не просто поток байт, а массив структур.
(неисключено что всё зависило от носителя данных, т.е. читать можно только с минимальным размером... строго по килобайту. Но если fread всё-равно вызовет read(), кто знает)
В наше время читают по байтам (size=1) , с перемноженным count-ом

Правка: 13 окт. 2018 8:05

}:+()___ [Smile]Постоялецwww13 окт. 20188:05#2
Вот поэтому я обычно использую POSIX вариант всего этого. Тоже стандарт, но гораздо более прямой.
Под *nix сишные варианты все равно через него сделаны, а под виндой стандартным fopen, по любому, пользоваться нельзя и приходится городить костыли что так, что эдак.
DelfigamerПостоялецwww13 окт. 20188:14#3
Panzerschrek[CN]
> почему mode - строка? Почему не флаги?
char занимает в два раза меньше, чем int, поэтому вместо
int flags[] = {FILE_FLAG_READ, FILE_FLAG_BINARY, FILE_FLAG_ADVANCED, 0};
FILE* file = fopen(path, flags);
использовали
char flags[] = {FILE_FLAG_READ, FILE_FLAG_BINARY, FILE_FLAG_ADVANCED, 0};
FILE* file = fopen(path, flags);
А раз флаги - это char, то для экономии места решили вместо FILE_FLAG_*** использовать символы:
char flags[] = {'r', 'b', '+', 0};
FILE* file = fopen(path, flags);
Ну а символьный char[] вполне записывается и в виде строки:
FILE* file = fopen(path, "rb+");
Ещё такая особенность - разные системы по-разному работают с файлами. Строковый формат очень легко расширяется - одна и та же функция работает и в каком-нибудь RtOS, поддерживая только самый скелет из "rwa+", так и в каком-нибудь Windows 10, где вместе с режимом передаётся формат, кодировка, write-through, наследование хенлда, политика буферизации (последовательная/рандомная) и флаг временного файла. char* - это просто и в то же время очень гибко.

Panzerschrek[CN]
> Зачем тут size и count?
Затем, что эта функция читает не байты, а целые записи размером size. Если ты вызовешь

int nums[10] = {};
size_t count = fread(nums, sizeof(nums[0]), countof(nums), stream);
на файле размером 11 байт, то функция вернёт count == 2 и ftell(stream) == 8.
Зачем это нужно? Не знаю. Помню только, что было очень весело, когда я перепутал аргументы и поставил единицу в count.

Panzerschrek[CN]
> Но почему в этой функции файл передаётся первым аргументом, а во всяких fread,
> fwrite - последним?
А чёрт его знает. Опять тяжёлое наследие юникса, наверно.

Panzerschrek[CN]
> Глядя на всё вышеизложенное, хочется спросить - что употребляли создатели всего
> этого? Как Международная Организация Стандартизации позволила оформить весь
> этот бред как стандарт?
Это ты ещё в ios не вникал, после него cstdio будет казаться кавайной няшкой.

Правка: 13 окт. 2018 8:17

innuendoПостоялецwww13 окт. 20189:25#4
Delfigamer
> Это ты ещё в ios не вникал, после него cstdio будет казаться кавайной няшкой.

точно :)

Panzerschrek[CN]
> Как могли додуматься до такого подхода?

я тоже думал над этим вопросом и понял что нехрена думать

lookidПостоялецwww13 окт. 20189:56#5
Panzerschrek[CN]
20-30 лет назад все всё писали на С. И всем было ОК. Это щас только нет ОК.
Ghost2Постоялецwww13 окт. 201810:02#6
Delfigamer

> char занимает в два раза меньше, чем int, поэтому вместо
Там все варианты помещаются в 8 бит.

Саша123Постоялецwww13 окт. 201810:09#7
Ghost2
> Там все варианты помещаются в 8 бит.
В восемь бит помещается 8 флагов.
Ок, допустим, на данный момент у нас есть не более 8 флагов.
Но расширяемость нужно предусмотреть, нет?

Правка: 13 окт. 2018 10:09

AlikberovПостоялецwww13 окт. 201810:11#8
Panzerschrek[CN]
> почему mode - строка? Почему не флаги? Как могли додуматься до такого подхода?
> С флагами работать понятно как, но строку надо ведь парсить.
Раньшe тоже не мог понять, пока не познакомился с PHP.
И фишка в том, что не нужно константы флагов за собою багажом таскать.
Только взгляните на TAR, где вместо бинарных величин используются восьмиричные ASCII, будто кто-то руками голыми их ковырять будет.

P.S.: Кто-то меня критикует, несмотря на жесть в некоторых местах и операционках… %-))

=A=L=X=Забаненwww13 окт. 201810:14#9
Panzerschrek[CN]
> Но почему в этой функции файл передаётся первым аргументом, а во всяких fread,
> fwrite - последним? Какая-то неконсистентность.

Скорее всего потому что если бы первым аргументом был бы offset, то это вызвало бы еще больше вопросов - почему первый аргумент непонятно что вообще.
Логика видимо в том, что на первом месте находится главное значение над которым функция работает - символ, буфер и его размер и т.п., а FILE* это контекст.
В случае же fseek сам FILE* и является значением над которым функция работает.
Но тут можно вспомнить серию fprintf - где опять таки из-за эллипсиса FILE* опять попадает на первое место.
В общем да, как по первому соображению сделали, так и осталось на века без рефакторинга, хотя он реально очень просится.
В копилку могу напомнить свою аналогичную тему: https://gamedev.ru/flame/forum/?id=234823

exchgПостоялецwww13 окт. 201810:16#10
Panzerschrek[CN]
> почему mode - строка? Почему не флаги? Как могли додуматься до такого подхода?
> С флагами работать понятно как, но строку надо ведь парсить.
Потому что это обертка над системными флагами. Будь место строки флаги для файлов,
все равно придется их парсить/мапить.
1 frag / 2 deathsЗабаненwww13 окт. 201810:53#11
Delfigamer
> int flags[] = {FILE_FLAG_READ, FILE_FLAG_BINARY, FILE_FLAG_ADVANCED, 0};
Как. Как? КАК?! Как ты мог додуматься до такого бредового использования инта?! КАК?! КААААААААК?!
+ чё так не сделать
gudleifrПостоялецwww13 окт. 201811:04#12
exchg
> Потому что это обертка над системными флагами.
Не обертка. Это сами флаги. У C вообще нет своих библиотек - он пользуется библиотеками UNIX (т.к. и сам является его частью). Тоже можно сказать и о самом понятии файла. Все это существует сейчас только постольку, поскольку новые системы эмулируют старый UNIX.
DelfigamerПостоялецwww13 окт. 201811:16#13
1 frag / 2 deaths
Тебе 16 бит всегда на всё хватает?
Panzerschrek[CN]Участникwww13 окт. 201811:25#14
skalogryz
> Они не являются организацией оценивающее качество, они просто принимают
> предложения на которые согласны, более менее все участники индустрии.
Короче, стандартизуют всякое говно неглядя.
Если завтра к ним придёт группа содомитов и предложит стандартизировать анальный секс - они это сделают.

> Расширяемость. Флагов на всех ненапосёшься и непредусмотришь.
Для платформоспецифифических нужд можно запилить fopen_ext с двадцатью параметрами.

Delfigamer
> char занимает в два раза меньше, чем int
А один бит char-а в 8 раз меньше занимает, чем весь char.

> а целые записи
Запись - сущность более высокого уровня. базовые функции чтения/записи должны быть более низкоуровневыми и работать с потоками байт.

lookid
> 20-30 лет назад все всё писали на С. И всем было ОК. Это щас только нет ОК.
Это не даёт ответа на вопрос, почему сделали так черезжопно.
swith удобнее внутри запилить, чем строку парсить.


Alikberov
> Раньшe тоже не мог понять, пока не познакомился с PHP.
> И фишка в том, что не нужно константы флагов за собою багажом таскать.
А чё, надо строки таскать?

=A=L=X=
> Логика видимо в том, что на первом месте находится главное значение над которым
> функция работает - символ, буфер и его размер и т.п., а FILE* это контекст
Именно поэтому FILE* на последнем месте в fread/fwrite?

exchg
> Потому что это обертка над системными флагами. Будь место строки флаги для
> файлов,
> все равно придется их парсить/мапить.

Страницы: 1 2 3 Следующая »

/ Форум / Флейм / Программирование

2001—2018 © GameDev.ru — Разработка игр