traduction - ¿Cómo funciona realmente el fread?
ftell (7)
De acuerdo con la especificación , los dos pueden ser tratados de manera diferente por la implementación.
Si su archivo tiene menos de 1000 bytes, fread(a, 1, 1000, stdin)
(lea 1000 elementos de 1 byte cada uno) copiará todos los bytes hasta EOF. Por otro lado, el resultado de fread(a, 1000, 1, stdin)
(leer 1 elemento de 1000 bytes) almacenado en a
no está especificado, porque no hay datos suficientes para terminar de leer el ''primer'' (y único) 1000 elemento byte
Por supuesto, algunas implementaciones aún pueden copiar el elemento ''parcial'' en tantos bytes como sea necesario.
La declaración de fread
es la siguiente:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
La pregunta es: ¿Hay alguna diferencia en el rendimiento de lectura de dos llamadas a fread
?
char a[1000];
-
fread(a, 1, 1000, stdin);
-
fread(a, 1000, 1, stdin);
¿Leerá 1000
bytes a la vez cada vez?
Eso sería detalles de implementación. En glibc, los dos son idénticos en rendimiento, ya que se implementa básicamente como (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;
}
Tenga en cuenta que la C y POSIX el estándar no garantiza que se deba leer un objeto completo de tamaño de size
cada vez. Si no se puede leer un objeto completo (por ejemplo, stdin
solo tiene 999 bytes pero ha solicitado el size == 1000
), el archivo se dejará en un estado interdeterminado (C99 §7.19.8.1 / 2).
Editar: vea las otras respuestas sobre POSIX.
Puede haber o no diferencia en el rendimiento. Hay una diferencia en semántica.
fread(a, 1, 1000, stdin);
intenta leer 1000 elementos de datos, cada uno de los cuales tiene 1 byte de longitud.
fread(a, 1000, 1, stdin);
intenta leer 1 elemento de datos que tiene 1000 bytes de longitud.
Son diferentes porque fread()
devuelve la cantidad de elementos de datos que pudo leer, no la cantidad de bytes. Si llega al final del archivo (o una condición de error) antes de leer los 1000 bytes completos, la primera versión debe indicar exactamente cuántos bytes se leyeron; el segundo solo falla y devuelve 0.
En la práctica, es probable que simplemente llame a una función de nivel inferior que intente leer 1000 bytes e indique cuántos bytes realmente leyó. Para lecturas más grandes, puede hacer múltiples llamadas de bajo nivel. El cálculo del valor que será devuelto por fread()
es diferente, pero el gasto del cálculo es trivial.
Puede haber una diferencia si la implementación puede decir, antes de intentar leer los datos, que no hay suficientes datos para leer. Por ejemplo, si está leyendo desde un archivo de 900 bytes, la primera versión leerá los 900 bytes y devolverá 900, mientras que el segundo podría no molestarse en leer nada. En ambos casos, el indicador de posición del archivo avanza por el número de caracteres leídos con éxito, es decir, 900.
Pero, en general, probablemente debería elegir cómo llamarlo según la información que necesita de él. Lea un solo elemento de datos si una lectura parcial no es mejor que no leer nada en absoluto. Lea en trozos más pequeños si las lecturas parciales son útiles.
Puede que no haya diferencia en el rendimiento, pero esas llamadas no son las mismas.
-
fread
devuelve la cantidad de elementos leídos, por lo que esas llamadas devolverán valores diferentes. - Si un elemento no puede leerse por completo, su valor es indeterminado:
Si se produce un error, el valor resultante del indicador de posición del archivo para la transmisión es indeterminado. Si se lee un elemento parcial, su valor es indeterminado. (ISO / IEC 9899: TC2 7.19.8.1)
No hay mucha diferencia en la implementación de glibc , que solo multiplica el tamaño del elemento por la cantidad de elementos para determinar cuántos bytes leer y divide la cantidad leída por el tamaño del miembro al final. Pero la versión que especifica un tamaño de elemento de 1 siempre le indicará la cantidad correcta de bytes leídos. Sin embargo, si solo le interesan los elementos completamente leídos de cierto tamaño, usar la otra forma le evita hacer una división.
Quería aclarar las respuestas aquí. fread realiza IO protegido. Los usos reales de los tamaños de bloque de lectura se determinan mediante la implementación C que se utiliza.
Todas las bibliotecas C modernas tendrán el mismo rendimiento con las dos llamadas:
fread(a, 1, 1000, file);
fread(a, 1000, 1, file);
Incluso algo como:
for (int i=0; i<1000; i++)
a[i] = fgetc(file)
Debería dar como resultado los mismos patrones de acceso al disco, aunque fgetc sería más lento debido a más llamadas a las bibliotecas c estándar y, en algunos casos, a la necesidad de un disco para realizar búsquedas adicionales que de otro modo habrían sido optimizadas.
Volviendo a la diferencia entre las dos formas de fread. El primero devuelve la cantidad real de bytes leídos. Este último devuelve 0 si el tamaño del archivo es menor que 1000, de lo contrario devuelve 1. En ambos casos, el búfer se rellenará con los mismos datos, es decir, el contenido del archivo hasta 1000 bytes.
En general, es probable que desee mantener el 2 ° parámetro (tamaño) configurado en 1, de modo que obtenga el número de bytes leídos.
Una forma más de oración http://pubs.opengroup.org/onlinepubs/000095399/functions/fread.html es notable
La función fread () leerá en la matriz apuntada por ptr hasta los elementos nitems cuyo tamaño se especifica por tamaño en bytes, desde la secuencia a la que apunta la transmisión. Para cada objeto, las llamadas de tamaño se realizarán a la función fgetc () y los resultados se almacenarán , en el orden leído, en una matriz de caracteres sin signo que se superpondrá exactamente al objeto.
¡Fgetc () ... accederá a la inserción en ambos casos!
fread
llama a getc
internamente. en Minix
número de veces que se llama a getc
es simplemente size*nmemb
por lo tanto, cuántas veces se getc
a getc
depende del producto de estas dos. Entonces, tanto fread(a, 1, 1000, stdin)
como fread(a, 1000, 1, stdin)
ejecutarán getc
1000=(1000*1)
veces. Aquí está la implementación fread
de fread
de Minix
size_t fread(void *ptr, size_t size, size_t nmemb, register FILE *stream){
register char *cp = ptr;
register int c;
size_t ndone = 0;
register size_t s;
if (size)
while ( ndone < nmemb ) {
s = size;
do {
if ((c = getc(stream)) != EOF)
*cp++ = c;
else
return ndone;
} while (--s);
ndone++;
}
return ndone;
}