2011-03-16 24 views
22

Stavo codificando un C++ per un piccolo progetto di hobby quando ho notato che sto usando le operazioni in stile C per accedere all'IO (printf, fopen, ecc.).Stream C++ contro IO in stile C?

È considerato "cattiva pratica" coinvolgere le funzioni C in progetti C++? Quali sono i vantaggi dell'utilizzo di stream su un accesso IO in stile C?

risposta

38

Questa è una riscaldata argomento.

Alcune persone preferiscono utilizzare il C++ IO dato che sono sicuri per il tipo (non è possibile avere divergenze tra il tipo dell'oggetto e il tipo specificato nella stringa di formato) e fluiscono più naturalmente con il resto del C++ modo di codifica.

Tuttavia, vi sono anche argomenti per le funzioni C IO (i miei preferiti personali). Alcuni di essi sono:

  • Si integrano più facilmente con localizzazione, come l'intera stringa di localizzare non è rotto in stringhe più piccole, e con qualche implementazione localizzatore possono riordinare l'ordine del valore inserito, spostarli in la stringa, ...
  • È possibile visualizzare direttamente il formato del testo che verrà scritto (questo può essere molto difficile con gli operatori di streaming).
  • Poiché non c'è alcuna inlining e solo una istanza della funzione printf, il codice generato è più piccolo (questo può essere importante nell'ambiente embedded).
  • Più veloce della funzione C++ in alcune implementazioni.

Personalmente, non considererei una cattiva pratica utilizzare il flusso C in codice C++. Some organisations consiglia anche di usarli su flusso C++. Quello che considererei uno stile negativo è quello di utilizzare entrambi nello stesso progetto. La coerenza è la chiave qui penso.


Come altri hanno notato, in un tempo relativamente grande progetto, si sarebbe probabilmente non usarli direttamente, ma si usa un set di funzione wrapper (o classi), che sarebbe meglio si adattano al vostro standard di codifica, e la vostra bisogni (localizzazione, tipo sicurezza, ...). Puoi utilizzare l'una o l'altra interfaccia IO per implementare questa interfaccia di livello superiore, ma probabilmente ne userai solo una.


Edit: l'aggiunta di alcune informazioni circa il vantaggio della funzione di famiglia printf formattazione relative alla localizzazione. Si prega di notare che tali informazioni sono valide solo per alcune implementazioni.

È possibile utilizzare %m$ anziché % per fare riferimento a un parametro per indice anziché a un riferimento sequenziale. Questo può essere usato per riordinare i valori nella stringa formattata. Il seguente programma scriverà Hello World! sullo standard output.

#include <stdio.h> 
int main() { 
    printf("%2$s %1$s\n", "World!", "Hello"); 
    return 0; 
} 

Considerate tradurre questo codice C++:

if (nb_files_deleted == 1) 
    stream << "One file "; 
else 
    stream << nb_file_deleted << " files "; 
stream << removed from directory \"" << directory << "\"\n"; 

Questo può essere davvero difficile. Con printf (e una libreria come gettext per gestire la localizzazione), il codice non è mescolato con la stringa. Possiamo quindi passare la stringa al team di localizzazione e non sarà necessario aggiornare il codice se ci sono casi particolari in alcune lingue (in alcune lingue, se il conteggio dell'oggetto è 0, si usa una forma plurale, in un'altra lingua, ci sono tre forme una per singolare, una quando ci sono due oggetti e una forma plurale, ...).

printf (ngettext ("One file removed from directory \"%2$s\"", 
        "%1$d files removed from directory \"%2$s\"", 
        n), 
     n, dir); 
+2

+1 per il punto di localizzazione. Ma come riordini i valori in printf? –

+2

Ho aggiornato il mio post per spiegare come riordinare i valori in 'printf' (suggerimento:'% m $ '). –

+0

Grazie per l'aggiornamento. Se potessi, invierei ancora una volta. –

3

Per uno, non è necessario convertire gli oggetti C++ (in particolare string s) in moduli compatibili C prima.

+1

Sì, mi stanco un po 'di dover scrivere 'str.c_str()' tutto il tempo ... – gablin

3

IMHO, un vero programmatore C++ cerca di fare le cose in modo C++ idiomatico; il programmatore convertito C cerca di aggrapparsi ai vecchi modi di fare le cose. Ha a che fare con la leggibilità e la coerenza.

+16

Un programmatore pragmatico utilizza il miglior strumento disponibile ... – PeterSW

5

Nulla può essere considerato una cattiva pratica se ha uno scopo preciso. Voglio dire, se IO è il collo di bottiglia del programma, allora sì, l'IO in stile C funziona più velocemente di C++ IO. Ma se non lo è, vorrei andare con l'approccio di flusso C++. Cuz it's cuter :)

6

Per un piccolo progetto di hobby, mi piacerebbe andare con i flussi di C++ io più sicuri del tipo.

Abbastanza divertente, non ho mai visto un progetto non banale di vita reale che utilizza uno di essi. In tutti i casi abbiamo utilizzato alcune astrazioni create sopra l'API del sistema operativo nativo per l'IO.

7

printf e gli amici sono orrendamente pericoloso rispetto al <iostream>, e non possono essere estesi, oltre naturalmente fopen e gli amici non hanno Raii, il che significa che se non hai dimostrato con un profiler che è sicuramente bisogno la differenza di prestazioni (che si hai dimostrato che esiste sulla tua piattaforma e nel tuo codice), dovresti essere un idiota per printf.

Modifica: La localizzazione è una cosa interessante che non avevo considerato. Non ho mai localizzato alcun codice e non posso commentare la relativa capacità di localizational printf e <iostream>

+3

AFAIK, la localizzazione di base viene eseguita estraendo stringhe letterali dal programma (che sono circondate da una chiamata a una funzione di traduzione) e che le persone traducono quelle stringhe. Immagina di dover tradurre e costruire frasi significative dai frammenti di frase che ottieni con cout. - Boost.Format può aiutarti con questo, però. – UncleBens

3

E 'considerato "cattiva pratica" per coinvolgere le funzioni C in progetti C++?

Di solito, il file di codice IO deve essere incapsulato in un implementazione della classe o funzione. Non considererei le eventuali scelte che fai nelle implementazioni incapsulate come "cattive pratiche", riservo quel termine per ciò che riguarda l'utente della tua biblioteca o codice (cioè l'interfaccia). Se si espone il meccanismo di IO del file nell'interfaccia, quindi, IMO, è una cattiva pratica se si utilizza il flusso di I/O o le funzioni IO in stile C.

Direi piuttosto che le funzioni IO in stile C sono (probabilmente sempre) la scelta peggiore.

Quali sono i vantaggi dell'utilizzo di flussi su accesso IO in stile C?

In primo luogo, si integrano meglio con standard C++ costruisce come std::string. Si integrano abbastanza bene con STL <algorithms>. E consentono di creare operatori di lettura/scrittura personalizzati incapsulati (< < e >>) in modo che le classi personalizzate sembrino quasi dei tipi primitivi quando si tratta di eseguire operazioni IO.

Infine, i flussi IO in C++ possono utilizzare il meccanismo di eccezione per segnalare errori nel flusso o operazioni di lettura/scrittura. Questi rendono il codice IO del file molto più bello, evitando il terribile aspetto dei meccanismi del codice di errore (sequenza di istruzioni if ​​e brutti cicli while, che controllano il codice di errore dopo ogni operazione).

+0

In tal caso non mi devo preoccupare, poiché incapsulare il codice IO in una classe è esattamente ciò che ho fatto. =) – gablin

3

Come regola generale, si dovrebbe preferire operatori C++, sono:

- Tipo di sicurezza. Non si rischia di passare un doppio in cui il formato richiede un numero intero.

- Estendibile. Puoi scrivere i tuoi inserter e gli extractor e usarli.

- Estendibile. È possibile definire i propri manipolatori (con il significato logico specifico dell'applicazione ) e utilizzarli. Se si desidera modificare il formato di tutti i WidgitNumber (internamente, un int) nell'output, si modifica il manipolatore ; non è necessario trovare tutte le istruzioni di formato in cui% d è un WidgitNumber.

- Estendibile. Puoi scrivere i tuoi lavandini e le tue fonti, e questi possono inoltrare ad altri sink e sorgenti, filtrare o espandendo l'input o l'output come desiderato.

(FWIW: non credo che abbia mai scritto un programma che non ha utilizzato personalizzato >> e < < operatori, manipolatori personalizzati e su misura streambuf di.)

5

Vantaggi

  • Tipo di sicurezza: i tipi di argomenti di C++ operazioni di streaming vengono controllati al momento della compilazione, mentre printf argomenti sono passati attraverso ... causare un comportamento indefinito se non corrispondono la formattazione.
  • Gestione risorse: gli oggetti di flusso C++ dispongono di distruttori per la chiusura di handle di file, buffer liberi e altro. I flussi C richiedono di ricordare di chiamare fclose.

Svantaggi

  • Performance: questo dipende dalla realizzazione, naturalmente, ma ho trovato la formattazione con i flussi C++ ad essere notevolmente più lento del printf formattazione equivalente.
2

È considerato "cattiva pratica" coinvolgere le funzioni C in progetti C++?

No. Le funzioni C sono spesso utilizzate in progetti C++. Per quanto riguarda i flussi, ad esempio, Google C++ Style Guide, è consigliabile utilizzarli solo in casi limitati, ad esempio "ad hoc, locali, leggibili e indirizzati ad altri sviluppatori piuttosto che agli utenti finali".

Quali sono i vantaggi dell'utilizzo degli stream tramite l'accesso IO in stile C?

I principali vantaggi sono di tipo sicurezza ed estensibilità. Tuttavia gli stream C++ presentano gravi difetti, vedere the answers to this question, ad esempio problemi di localizzazione, segnalazione di errori insufficienti, problemi di codice e problemi di prestazioni in alcune implementazioni.

+0

In realtà non è vero che la Guida allo stile di Google C++, ad esempio, consiglia di utilizzare I/O in stile C su I/O in stile C++. Si dice che è meglio usare librerie alternative per usi più complessi, ma altrimenti utilizzare i flussi quando necessario. Non menziona nemmeno il sistema I/O C – Triskeldeian

+0

Devono averlo cambiato. Ho aggiornato la risposta, grazie! – vitaut