Qual è la logica per cui fread / fwrite prende le dimensioni e conta come argomenti?
Domanda
Abbiamo discusso qui sul motivo per cui fread e fwrite prendono una dimensione per membro e contano e restituiscono il numero di membri letti / scritti anziché prendere semplicemente un buffer e una dimensione. L'unico uso che potremmo trovare è se vuoi leggere / scrivere una serie di strutture che non sono uniformemente divisibili per l'allineamento della piattaforma e quindi sono state imbottite ma che non possono essere così comuni da giustificare questa scelta nel design.
Da FREAD (3) :
La funzione fread () legge nmemb elementi di dati, ogni dimensione byte, dal flusso indicato dal flusso, memorizzandoli nella posizione indicata di ptr.
La funzione fwrite () scrive nmemb elementi di dati, ogni dimensione byte lungo, al flusso indicato dal flusso, ottenendoli dalla posizione dato da ptr.
fread () e fwrite () restituiscono il numero di elementi letti o scritti correttamente (cioè non il numero di caratteri). Se si verifica un errore, oppure il end-of-file viene raggiunto, il valore restituito è un conteggio breve degli articoli (o zero).
Soluzione
Si basa su come fread è implementato.
La specifica singola UNIX dice
Per ogni oggetto, le chiamate di dimensione devono essere fatto per la funzione fgetc () e il risultati memorizzati, nell'ordine letto, in una matrice di caratteri non firmati esattamente sovrapponendo l'oggetto.
fgetc ha anche questa nota:
Poiché fgetc () opera su byte, leggere un personaggio composto da più byte (o " un multi-byte carattere ") può richiedere più chiamate a fgetc ().
Ovviamente, questo precede le fantasiose codifiche di caratteri a byte variabile come UTF-8.
Il SUS osserva che questo è in realtà preso dai documenti ISO C.
Altri suggerimenti
La differenza tra fread (buf, 1000, 1, stream) e fread (buf, 1, 1000, stream) è che nel primo caso si ottiene un solo blocco di 1000 byte o nuthin, se il file è più piccolo e nel secondo caso ottieni tutto nel file meno e fino a 1000 byte.
Si tratta di pure speculazioni, tuttavia ai giorni nostri (alcuni sono ancora in circolazione) molti filesystem non erano semplici flussi di byte su un disco rigido.
Molti file system erano basati su record, quindi per soddisfare tali filesystem in modo efficiente, dovrai specificare il numero di elementi ("record"), consentendo a fwrite / fread di operare sulla memoria come record, non solo flussi di byte.
Qui, lasciami riparare quelle funzioni:
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);
}
Per quanto riguarda una logica dei parametri per fread ()
/ fwrite ()
, ho perso la mia copia di K & amp; R molto tempo fa, quindi posso solo immaginare . Penso che una probabile risposta sia che Kernighan e Ritchie abbiano semplicemente pensato che eseguire l'I / O binario sarebbe stato più naturale sugli array di oggetti. Inoltre, potrebbero aver pensato che l'I / O a blocchi sarebbe stato più veloce / più facile da implementare o altro su alcune architetture.
Anche se lo standard C specifica che fread ()
e fwrite ()
devono essere implementati in termini di fgetc ()
e fputc ()
, ricorda che lo standard è nato molto dopo che C è stato definito da K & amp; R e che le cose specificate nello standard potrebbero non essere state nelle idee dei designer originali. È anche possibile che le cose dette in K & amp; R "Il linguaggio di programmazione C" potrebbe non essere la stessa di quando la lingua è stata progettata per la prima volta.
Infine, ecco cosa ha da dire P.J. Plauger su fread ()
in " The Standard C Library " ;:
Se l'argomento
size
(secondo) è maggiore di uno, non è possibile determinare se la funzione legge anchesize - 1
caratteri aggiuntivi oltre a quanto riportato. Di norma, è meglio chiamare la funzione comefread (buf, 1, size * n, stream);
anzichéfread (buf, size, n, stream);
Bascialmente, sta dicendo che l'interfaccia di fread ()
è rotta. Per fwrite ()
osserva che, "gli errori di scrittura sono generalmente rari, quindi questo non è un grosso difetto " - una dichiarazione con cui non sarei d'accordo.
Probabilmente risale al modo in cui è stato implementato l'I / O dei file. (indietro nel giorno) Potrebbe essere stato più veloce scrivere / leggere su file in blocchi piuttosto che scrivere tutto in una volta.
Penso che sia perché a C manca la funzione di sovraccarico. Se ce ne fosse, la dimensione sarebbe ridondante. Ma in C non puoi determinare la dimensione di un elemento array, devi specificarne uno.
Considera questo:
int intArray[10];
fwrite(intArray, sizeof(int), 10, fd);
Se fwrite ha accettato il numero di byte, è possibile scrivere quanto segue:
int intArray[10];
fwrite(intArray, sizeof(int)*10, fd);
Ma è solo inefficiente. Avrai dimensioni (int) volte più chiamate di sistema.
Un altro punto da tenere in considerazione è che di solito non si desidera che una parte di un elemento dell'array sia scritta in un file. Vuoi l'intero intero o niente. fwrite restituisce un numero di elementi scritti correttamente. Quindi se scopri che sono scritti solo 2 byte bassi di un elemento, cosa faresti?
Su alcuni sistemi (a causa dell'allineamento) non è possibile accedere a un byte di un numero intero senza crearne una copia e spostarlo.
Avere argomenti separati per dimensione e conteggio potrebbe essere vantaggioso per un'implementazione che può evitare di leggere qualsiasi record parziale. Se si dovessero usare letture a byte singolo da qualcosa come una pipe, anche se si usassero dati in formato fisso, si dovrebbe consentire la possibilità che un record venga suddiviso su due letture. Se potesse invece richiedere ad es. una lettura non bloccante di un massimo di 40 record di 10 byte ciascuno quando sono disponibili 293 byte e il sistema restituisce 290 byte (29 record interi) lasciando 3 byte pronti per la lettura successiva, sarebbe molto più conveniente.
Non so fino a che punto le implementazioni di fread possano gestire tali semantiche, ma potrebbero certamente essere utili su implementazioni che potrebbero promettere di supportarle.