¿Cuál es la razón para que fread / fwrite tome tamaño y cuente como argumentos?

StackOverflow https://stackoverflow.com/questions/295994

  •  08-07-2019
  •  | 
  •  

Pregunta

Tuvimos una discusión aquí en el trabajo sobre por qué fread y fwrite toman un tamaño por miembro y cuentan y devuelven el número de miembros leídos / escritos en lugar de simplemente tomar un búfer y un tamaño. El único uso que podríamos encontrar es si desea leer / escribir una serie de estructuras que no son divisibles por la alineación de la plataforma y, por lo tanto, se han rellenado, pero eso no puede ser tan común como para garantizar esta elección. en diseño.

De FREAD (3) :

  

La función fread () lee nmemb elementos de datos, cada tamaño de bytes de longitud,   desde la secuencia apuntada por secuencia, almacenándolas en la ubicación dada   por ptr.

     

La función fwrite () escribe elementos de datos nmemb, cada tamaño de bytes   largo, a la secuencia apuntada por secuencia, obteniéndolos desde la ubicación   dado por ptr.

     

fread () y fwrite () devuelven el número de elementos leídos o escritos correctamente   (es decir, no el número de caracteres). Si ocurre un error, o el   se alcanza el final del archivo, el valor de retorno es un recuento corto de elementos (o cero).

¿Fue útil?

Solución

Se basa en cómo se implementa fread .

La especificación UNIX única dice

  

Para cada objeto, las llamadas de tamaño serán   hecho a la función fgetc () y el   resultados almacenados, en el orden leído, en   una serie de caracteres sin signo exactamente   superposición del objeto.

fgetc también tiene esta nota:

  

Dado que fgetc () opera en bytes,   leyendo un personaje que consiste en   bytes múltiples (o " un byte múltiple   carácter ") puede requerir múltiples llamadas   a fgetc ().

Por supuesto, esto es anterior a las codificaciones de caracteres de bytes variables elegantes como UTF-8.

El SUS señala que esto realmente se toma de los documentos ISO C.

Otros consejos

La diferencia entre fread (buf, 1000, 1, stream) y fread (buf, 1, 1000, stream) es que, en el primer caso, solo obtiene un fragmento de 1000 bytes o nuthin, si el archivo es más pequeño y en el segundo caso, obtienes todo en el archivo de menos de 1000 bytes.

Esto es pura especulación, sin embargo, en el pasado (algunos todavía existen) muchos sistemas de archivos no eran simples secuencias de bytes en un disco duro.

Muchos sistemas de archivos se basaron en registros, por lo tanto, para satisfacer dichos sistemas de archivos de manera eficiente, tendrá que especificar el número de elementos ("registros"), permitiendo que fwrite / fread opere en el almacenamiento como registros, no solo secuencias de bytes.

Aquí, déjame arreglar esas funciones:

size_t fread_buf( void* ptr, size_t size, FILE* stream)
{
    return fread( ptr, 1, size, stream);
}


size_t fwrite_buf( void const* ptr, size_t size, FILE* stream)
{
    return fwrite( ptr, 1, size, stream);
}

En cuanto a la justificación de los parámetros para fread () / fwrite () , perdí mi copia de K & amp; R hace mucho tiempo, así que solo puedo adivinar . Creo que una respuesta probable es que Kernighan y Ritchie pueden haber pensado simplemente que realizar E / S binarias se haría de forma más natural en conjuntos de objetos. Además, pueden haber pensado que el bloque de E / S sería más rápido / fácil de implementar o lo que sea en algunas arquitecturas.

Aunque el estándar C especifica que fread () y fwrite () se implementarán en términos de fgetc () y fputc () , recuerde que el estándar entró en vigor mucho después de que K & amp; R definiera C y que las cosas especificadas en el estándar podrían no haber estado en las ideas originales de los diseñadores. Incluso es posible que las cosas se digan en K & amp; R's "The C Programming Language". podría no ser el mismo que cuando se diseñó el idioma por primera vez.

Finalmente, esto es lo que P.J. Plauger tiene que decir sobre fread () en " The Standard C Library " ;:

  

Si el argumento size (segundo) es mayor que uno, no puede determinar   si la función también lee hasta size - 1 caracteres adicionales más allá de lo que informa.   Como regla general, es mejor llamar a la función como fread (buf, 1, size * n, stream); en lugar de    fread (buf, tamaño, n, secuencia);

Básicamente, dice que la interfaz de fread () está rota. Para fwrite () señala que, "los errores de escritura son generalmente raros, por lo que este no es un gran defecto". - una declaración con la que no estaría de acuerdo.

Probablemente se remonta a la forma en que se implementó la E / S de archivo. (en el pasado) Podría haber sido más rápido escribir / leer en archivos en bloques que escribir todo de una vez.

Creo que es porque C carece de sobrecarga de funciones. Si hubiera alguno, el tamaño sería redundante. Pero en C no puede determinar el tamaño de un elemento de matriz, debe especificar uno.

Considera esto:

int intArray[10];
fwrite(intArray, sizeof(int), 10, fd);

Si fwrite acepta el número de bytes, podría escribir lo siguiente:

int intArray[10];
fwrite(intArray, sizeof(int)*10, fd);

Pero es simplemente ineficiente. Tendrá sizeof (int) veces más llamadas al sistema.

Otro punto que debe tenerse en cuenta es que generalmente no desea que una parte de un elemento de matriz se escriba en un archivo. Quieres todo el entero o nada. fwrite devuelve una serie de elementos escritos con éxito. Entonces, si descubre que solo se escriben 2 bytes bajos de un elemento, ¿qué haría?

En algunos sistemas (debido a la alineación) no se puede acceder a un byte de un número entero sin crear una copia y desplazamiento.

Tener argumentos separados para el tamaño y el recuento podría ser ventajoso en una implementación que puede evitar la lectura de registros parciales. Si se usaran lecturas de un solo byte de algo así como una tubería, incluso si se usaran datos de formato fijo, uno tendría que permitir la posibilidad de que un registro se dividiera en dos lecturas. En su lugar, podría solicitar p. Ej. una lectura sin bloqueo de hasta 40 registros de 10 bytes cada uno cuando haya 293 bytes disponibles, y que el sistema devuelva 290 bytes (29 registros completos) mientras deja 3 bytes listos para la próxima lectura, eso sería mucho más conveniente.

No sé hasta qué punto las implementaciones de fread pueden manejar tal semántica, pero ciertamente podrían ser útiles en implementaciones que podrían prometer apoyarlos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top