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

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

Страницы: 1 2 3 Следующая »
#0
(Правка: 7:25) 7:24, 13 окт. 2018

Рассмотрим интерфейс по работе с файлами в Сишке.

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

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 пишет в стандартный вывод, а не в заданный файл.


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

#1
(Правка: 8:05) 8:03, 13 окт. 2018

для структурных языков низлежайшее API может быть сколь угодно убогим.
ведь всегда можно написать православную обёртку.

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

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

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

#2
8:05, 13 окт. 2018

Вот поэтому я обычно использую POSIX вариант всего этого. Тоже стандарт, но гораздо более прямой.
Под *nix сишные варианты все равно через него сделаны, а под виндой стандартным fopen, по любому, пользоваться нельзя и приходится городить костыли что так, что эдак.

#3
(Правка: 8:17) 8:14, 13 окт. 2018

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 будет казаться кавайной няшкой.

#4
9:25, 13 окт. 2018

Delfigamer
> Это ты ещё в ios не вникал, после него cstdio будет казаться кавайной няшкой.

точно :)

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

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

#5
9:56, 13 окт. 2018

Panzerschrek[CN]
20-30 лет назад все всё писали на С. И всем было ОК. Это щас только нет ОК.

#6
10:02, 13 окт. 2018

Delfigamer

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

#7
(Правка: 10:09) 10:09, 13 окт. 2018

Ghost2
> Там все варианты помещаются в 8 бит.
В восемь бит помещается 8 флагов.
Ок, допустим, на данный момент у нас есть не более 8 флагов.
Но расширяемость нужно предусмотреть, нет?

#8
10:11, 13 окт. 2018

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

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

#9
10:14, 13 окт. 2018

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

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

#10
10:16, 13 окт. 2018

Panzerschrek[CN]
> почему mode - строка? Почему не флаги? Как могли додуматься до такого подхода?
> С флагами работать понятно как, но строку надо ведь парсить.
Потому что это обертка над системными флагами. Будь место строки флаги для файлов,
все равно придется их парсить/мапить.

#11
10:53, 13 окт. 2018

Delfigamer
> int flags[] = {FILE_FLAG_READ, FILE_FLAG_BINARY, FILE_FLAG_ADVANCED, 0};
Как. Как? КАК?! Как ты мог додуматься до такого бредового использования инта?! КАК?! КААААААААК?!

+ чё так не сделать
#12
11:04, 13 окт. 2018

exchg
> Потому что это обертка над системными флагами.
Не обертка. Это сами флаги. У C вообще нет своих библиотек - он пользуется библиотеками UNIX (т.к. и сам является его частью). Тоже можно сказать и о самом понятии файла. Все это существует сейчас только постольку, поскольку новые системы эмулируют старый UNIX.

#13
11:16, 13 окт. 2018

1 frag / 2 deaths
Тебе 16 бит всегда на всё хватает?

#14
11:25, 13 окт. 2018

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 Следующая »
ФлеймФорумПрограммирование