Qual è la logica per cui fread / fwrite prende le dimensioni e conta come argomenti?

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

  •  08-07-2019
  •  | 
  •  

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).

È stato utile?

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 anche size - 1 caratteri aggiuntivi oltre a quanto riportato.   Di norma, è meglio chiamare la funzione come fread (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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top