Как на самом деле работает fread?



декларация fread выглядит следующим образом:



size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);


вопрос: есть ли разница в производительности чтения двух таких вызовов fread:



char a[1000];



  1. fread(a, 1, 1000, stdin);

  2. fread(a, 1000, 1, stdin);


будет ли он читать 1000 байт сразу каждый раз?

799   7  

7 ответов:

может быть или не быть никакой разницы в производительности. Есть разница в семантике.

fread(a, 1, 1000, stdin);

пытается прочитать 1000 элементов данных, каждый из которых занимает 1 байт.

fread(a, 1000, 1, stdin);

пытается прочитать 1 элемент данных длиной 1000 байт.

они разные, потому что fread() возвращает количество элементов данных, которые он смог прочитать, а не количество байтов. Если он достигает конца файла (или состояния ошибки) перед чтением полной 1000 байты, первая версия должна точно указать, сколько байтов она прочитала; вторая просто терпит неудачу и возвращает 0.

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

может быть разница если реализация может сказать, прежде чем пытаться прочитать данные, что для чтения недостаточно данных. Например, если Вы читаете из 900-байтового файла, первая версия будет читать все 900 байт и возвращать 900, в то время как вторая может ничего не читать. В обоих случаях индикатор положения файла выдвигается на число символы успешно прочитано, т. е. 900.

но в целом, вы, вероятно, должны выбрать, как назвать его на основе того, что информация, которая вам нужна от него. Прочитайте один элемент данных, если частичное чтение не лучше, чем вообще ничего не читать. Читайте в меньших кусках, если частичные чтения полезны.

По данным спецификация, эти два могут рассматриваться по-разному по реализации.

Если ваш файл меньше 1000 байт fread(a, 1, 1000, stdin) (чтение 1000 элементов по 1 байту каждый) будет по-прежнему копировать все байты до EOF. С другой стороны, результат fread(a, 1000, 1, stdin) (читать 1 1000-байтовый элемент) хранится в a Не указано, потому что недостаточно данных для завершения чтения "первого" (и только) 1000-байтового элемента.

конечно, некоторые реализации могут по-прежнему копировать "частичный" элемент в столько байтов, сколько необходимо.

Это была бы деталь реализации. В glibc они идентичны по производительности, так как реализованы в основном как (Ref http://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iofread.c):

size_t fread (void* buf, size_t size, size_t count, FILE* f)
{
    size_t bytes_requested = size * count;
    size_t bytes_read = read(f->fd, buf, bytes_requested);
    return bytes_read / size;
}

обратите внимание, что C и POSIX стандарт не гарантирует полный объект размера size нужно читать каждый раз. Если весь объект не может быть прочитан (например,stdin только 999 байт, но вы просили size == 1000), то файл будет оставленный в неопределенном состоянии (C99 §7.19.8.1/2).

изменить: см. другие ответы о POSIX.

fread звонки getc внутренне. в Minix несколько раз getc называется просто size*nmemb так сколько раз getc будет называться зависит от продукт из этих двух. Так Что Оба fread(a, 1, 1000, stdin) и fread(a, 1000, 1, stdin) будет работать getc

там может быть никакой разницы в производительности, но эти вызовы не то же самое.

  • fread возвращает количество прочитанных элементов, поэтому эти вызовы будут возвращать разные значения.
  • если элемент не может быть полностью прочитан, его значение неопределенно:

Если происходит ошибка, в результате чего значение индикатора позиции файла для потока сомнительный. Если частичный элемент считывается, его значение не определено. (ISO / IEC 9899: TC2 7.19.8.1)

нет большой разницы в реализация glibc, который просто умножает размер элемента на количество элементов, чтобы определить, сколько байтов для чтения и делит количество прочитанных на размер элемента в конце. Но версия, указывающая размер элемента 1, всегда будет указывать вам правильное количество прочитанных байтов. Однако, если вы заботитесь только о полностью прочитанных элементах определенного размера, использование другой формы спасает вас от делать разделение.

еще одна форма предложения http://pubs.opengroup.org/onlinepubs/000095399/functions/fread.html примечательно

функция fread () должна считываться в массив, на который указывает ptr, до элементов nitems, размер которых определяется размером в байтах, из потока, на который указывает поток. для каждого объекта должны быть сделаны вызовы размера функции fgetc () и сохранены результаты, в порядке чтения, в массиве беззнаковых символов точно накладывается объект.

Inshort в обоих случаях данные будут доступны с помощью fgetc ()...!

Я хотел уточнить ответы здесь. fread выполняет буферизованный ввод-вывод. Фактические размеры блоков чтения, используемые fread, определяются используемой реализацией C.

все современные библиотеки C будут иметь одинаковую производительность с двумя вызовами:

fread(a, 1, 1000, file);
fread(a, 1000, 1, file);

даже что-то вроде:

for (int i=0; i<1000; i++)
  a[i] = fgetc(file)

должно привести к тем же шаблонам доступа к диску, хотя fgetc будет медленнее из-за большего количества вызовов стандартных библиотек c и в некоторых случаях необходимости в диске для выполнения дополнительных поисков, которые в противном случае были бы оптимизированы прочь.

возвращаясь к разнице между двумя формами fread. Первый возвращает фактическое количество прочитанных байтов. Последний возвращает 0, если размер файла меньше 1000, в противном случае она возвращает 1. В обоих случаях буфер будет заполнен одними и теми же данными, т. е. содержимым файла до 1000 байт.

В общем, вы, вероятно, хотите сохранить 2-й параметр (размер) равным 1, чтобы вы получаете количество прочитанных байтов.

Comments

    Ничего не найдено.