Come viene implementato l'I / O in C?

5

Il linguaggio di programmazione C dice che I / O non è incorporato in C e viene invece acceduto tramite stdio.h . Ma se stdio.h è scritto in C, in che modo stdio.h implementa I / O?

Ho guardato il codice sorgente e non lo capisco.

    
posta Challenger5 15.11.2016 - 06:33
fonte

5 risposte

4

Quando K & R scrive che I / O non è "incorporato in C", significa principalmente che le istruzioni I / O non fanno parte della grammatica della lingua. Al contrario, Fortran 77 ha istruzioni I / O distinte , come l'istruzione PRINT :

PRINT *, 'The value of X is', X

Le funzioni di libreria C stdio e le istruzioni I / O Fortran delegano tutte le operazioni di I / O al sistema sottostante. È solo che nel caso di C ignorano di dover analizzare e tradurre istruzioni I / O di alto livello in codice macchina.

    
risposta data 15.11.2016 - 23:02
fonte
7

Normalmente la libreria standard chiamerà qualcosa nel sistema operativo per gestire la lettura e la scrittura del file vero e proprio. Su POSIX (o simili) che sarebbero per lo più read e write , che possono leggere o scrivere file. Su Windows, normalmente sarà ReadFile e WriteFile . Windows fornisce anche ReadFileEx e WriteFileEx , ma sono principalmente per l'I / O asincrono, che la libreria standard non supporta (ancora).

Da lì, l'esecuzione in genere discenderà attraverso (almeno) un driver del file system, una cache del file system e un driver di periferica per il disco, SSD o qualunque tipo di dispositivo viene utilizzato per memorizzare il file in questione. In alternativa, i dati potrebbero passare attraverso un livello socket e da lì a un driver di dispositivo per un'interfaccia di rete.

I dettagli precisi del trasferimento dei dati sull'hardware variano (abbastanza ampiamente), ma in un caso tipico dell'hardware moderno gran parte di essi viene effettivamente gestito dal dispositivo di destinazione stesso. Sulla CPU si crea una lista di raccolta per l'output o una lista di dispersione per l'input. Questo è fondamentalmente solo una piccola parte delle tabelle delle pagine della CPU, per dire al dispositivo di destinazione quali pagine fisiche deve leggere (per l'output) o scrivere (per l'input).

Questo è necessario perché (almeno sulla maggior parte dei SO tipici) stai allocando memoria con indirizzi virtuali - ciò che il tuo programma vede come memoria "contigua" può essere sparsi in modo piuttosto casuale nella memoria fisica. La maggior parte dell'hardware 1 non è al corrente di quella traduzione degli indirizzi, quindi deve essere fornita con gli indirizzi fisici delle singole pagine di memoria in cui risiedono i tuoi dati.

Si noti inoltre che in un caso tipico (ad esempio, un file tipico su disco), ciò che si rilascia come una singola chiamata a fwrite potrebbe essere tradotto in un numero di operazioni I / O effettive con l'unità disco. Se scrivi parte di un settore, la tua scrittura potrebbe tradurre in lettura un intero settore in un buffer, sovrascrivendo parte di quel buffer, quindi scrivendo il buffer modificato sul disco.

1. Le principali eccezioni sono alcune schede video e gli adattatori di rete RDMA. Questi hanno memoria in cui il driver del dispositivo mantiene una copia shadow delle tabelle di conversione degli indirizzi della CPU, che l'hardware quindi usa per tradurre gli indirizzi, riducendo così il carico sulla CPU.

    
risposta data 15.11.2016 - 07:03
fonte
2

Le operazioni di I / O non fanno parte del linguaggio C nel senso che i nomi e le firme delle funzioni di I / O non sono magicamente noti nel programma. Invece è necessario un #include <stdio.h> per comunicare al compilatore i nomi e le firme delle funzioni di I / O.

L'implementazione di queste funzioni è nella libreria standard, che può essere o non essere scritta in C, sebbene per le funzioni di I / O è probabile che siano scritte in C e delegare del lavoro alle funzioni fornite dal sistema operativo sistema.

    
risposta data 15.11.2016 - 08:42
fonte
0

I driver di dispositivo sono molto dipendenti dall'hardware. Alcuni componenti hardware utilizzano l'I / O mappato in memoria (ovvero si legge / scrive su indirizzi di memoria dedicati per controllare dispositivi I / O). Altri hanno registri e opcode speciali. Mentre il primo potrebbe essere gestito con C, varia ancora da macchina a macchina (tempi, indirizzi). Il secondo ha semplicemente bisogno di un assemblatore per parlare correttamente con l'hardware. Comunque puoi usare C in questo caso, ma contiene molto codice diretto di assemblatore. Quindi in realtà

accessed through stdio.h

significa che dietro questa intestazione troverai roba di livello molto basso.

    
risposta data 15.11.2016 - 08:03
fonte
0

Ci sono alcune risposte, ma nessuna parla di File Descriptor / Handle, che è il nucleo di come l'IO è gestito dal sistema operativo.

Quando apri un file, un socket o qualsiasi altra cosa tu usi per IO, ottieni un puntatore a un Descrittore di fiammata / FD (linux) o un handle in Windows che è stesso .

Fondamentalmente il sistema operativo, che sia Linux o Windows, ha una tabella di questi FD / Handle e quando si chiama un IO su di essi, non si sta scrivendo nel file, si sta chiedendo al sistema operativo che vuoi eseguire l'operazione X sulla maniglia Y . Queste cose sono di così basso livello (vedi la risposta di @JerryCoffin) che non lo fai tu stesso, invece usi la libreria stdio che ti avvolge per te. Il resto è il sistema operativo, con tutti i driver e l'hardware che gestirà le cose per te.

Questo grazie a questa astrazione (driver FD / Handles + OS +) che puoi usare le operazioni su File in modo abbastanza trasparente qualunque sia il disco formattato in FAT / NTFS / EXT4. Sebbene ci siano alcuni limiti (es .: FAT 32: non più del file 4G).

    
risposta data 15.11.2016 - 11:04
fonte

Leggi altre domande sui tag