Risposte:
Sono sorpreso che tutti in questa domanda affermino che std::coutè molto meglio di printf, anche se la domanda ha solo chiesto differenze. Ora, c'è una differenza - std::coutè C ++, ed printfè C (tuttavia, è possibile utilizzarlo in C ++, proprio come quasi ogni altra cosa da C). Ora, sarò onesto qui; entrambi printfe std::couthanno i loro vantaggi.
std::coutè estensibile. So che la gente dirà che printfè anche estensibile, ma tale estensione non è menzionata nello standard C (quindi dovresti usare funzionalità non standard - ma non esiste nemmeno una funzionalità non standard comune), e tali estensioni sono una lettera (quindi è facile entrare in conflitto con un formato già esistente).
Diversamente printf, std::coutdipende completamente dal sovraccarico dell'operatore, quindi non ci sono problemi con i formati personalizzati: tutto ciò che devi fare è definire una subroutine std::ostreamcome primo argomento e il tuo tipo come secondo. Come tale, non ci sono problemi di spazio dei nomi - finché hai una classe (che non è limitata a un carattere), puoi avere un std::ostreamsovraccarico di lavoro per questo.
Tuttavia, dubito che molte persone vorrebbero estendere ostream(ad essere onesti, raramente ho visto tali estensioni, anche se sono facili da realizzare). Tuttavia, è qui se ne hai bisogno.
Come potrebbe essere facilmente notare, sia printfe std::coututilizzare sintassi diversa. printfusa la sintassi delle funzioni standard usando la stringa di pattern e gli elenchi di argomenti a lunghezza variabile. In realtà, printfè un motivo per cui C li ha: i printfformati sono troppo complessi per essere utilizzabili senza di essi. Tuttavia, std::coututilizza un'API diversa: l' operator <<API che restituisce se stessa.
In genere, ciò significa che la versione C sarà più corta, ma nella maggior parte dei casi non importa. La differenza si nota quando si stampano molti argomenti. Se devi scrivere qualcosa del genere Error 2: File not found., assumendo il numero di errore e la sua descrizione è segnaposto, il codice sarebbe simile a questo. Entrambi gli esempi funzionano in modo identico (beh, in qualche modo, std::endleffettivamente svuota il buffer).
printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;
Anche se questo non sembra troppo folle (è solo due volte più lungo), le cose diventano più folli quando si formattano gli argomenti, invece di stamparli. Ad esempio, la stampa di qualcosa di simile 0x0424è semplicemente pazza. Ciò è causato dalla std::coutmiscelazione dello stato e dei valori effettivi. Non ho mai visto un linguaggio in cui qualcosa del genere std::setfillsarebbe un tipo (diverso dal C ++, ovviamente). printfsepara chiaramente argomenti e tipo reale. Preferirei davvero mantenerne la printfversione (anche se sembra un po 'criptica) rispetto alla iostreamversione di essa (poiché contiene troppo rumore).
printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;
Questo è il vero vantaggio delle printfbugie. La printfstringa di formato è bene ... una stringa. Ciò rende davvero facile la traduzione, rispetto operator <<all'abuso di iostream. Supponendo che la gettext()funzione traduca e si desideri mostrare Error 2: File not found., il codice per ottenere la traduzione della stringa di formato mostrata in precedenza sarebbe simile al seguente:
printf(gettext("Error %d: %s.\n"), id, errors[id]);
Supponiamo ora di tradurre in Fictionish, dove il numero di errore si trova dopo la descrizione. La stringa tradotta sarebbe simile %2$s oru %1$d.\n. Ora, come si fa in C ++? Bene, non ne ho idea. Immagino che tu possa falsificare iostreamquali costrutti printfpuoi passare a gettext, o qualcosa, ai fini della traduzione. Certo, $non è lo standard C, ma è così comune che a mio avviso è sicuro da usare.
C ha molti tipi interi, così come C ++. std::coutgestisce tutti i tipi per te, mentre printfrichiede una sintassi specifica a seconda di un tipo intero (ci sono tipi non interi, ma l'unico tipo non intero che userai in pratica con printfè const char *(stringa C, che può essere ottenuta usando il to_cmetodo di std::string)). Ad esempio, per stampare size_t, è necessario utilizzare %zd, mentre int64_trichiederà l'utilizzo %"PRId64". Le tabelle sono disponibili su http://en.cppreference.com/w/cpp/io/c/fprintf e http://en.cppreference.com/w/cpp/types/integer .
\0Poiché printfutilizza le stringhe C anziché le stringhe C ++, non può stampare byte NUL senza trucchi specifici. In alcuni casi è possibile utilizzare %ccon '\0'come argomento, anche se questo è chiaramente un hack.
Aggiornamento: si scopre che iostreamè così lento che di solito è più lento del disco rigido (se si reindirizza il programma su file). La disabilitazione della sincronizzazione con stdiopuò essere d'aiuto, se è necessario produrre molti dati. Se la performance è una vera preoccupazione (invece di scrivere più righe su STDOUT), basta usare printf.
Tutti pensano che si preoccupino delle prestazioni, ma nessuno si preoccupa di misurarle. La mia risposta è che l'I / O è comunque un collo di bottiglia, non importa se lo usi printfo iostream. Penso che printf potrebbe essere più veloce da una rapida occhiata in assembly (compilato con clang usando l' -O3opzione del compilatore). Supponendo il mio esempio di errore, l' printfesempio fa meno chiamate rispetto coutall'esempio. Questo è int maincon printf:
main: @ @main
@ BB#0:
push {lr}
ldr r0, .LCPI0_0
ldr r2, .LCPI0_1
mov r1, #2
bl printf
mov r0, #0
pop {lr}
mov pc, lr
.align 2
@ BB#1:
Si può facilmente notare che due stringhe e 2(numero) vengono spinti come printfargomenti. Questo è tutto; non c'è nient'altro. Per confronto, questo viene iostreamcompilato per l'assemblaggio. No, non c'è allineamento; ogni singola operator <<chiamata indica un'altra chiamata con un'altra serie di argomenti.
main: @ @main
@ BB#0:
push {r4, r5, lr}
ldr r4, .LCPI0_0
ldr r1, .LCPI0_1
mov r2, #6
mov r3, #0
mov r0, r4
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
mov r0, r4
mov r1, #2
bl _ZNSolsEi
ldr r1, .LCPI0_2
mov r2, #2
mov r3, #0
mov r4, r0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_3
mov r0, r4
mov r2, #14
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_4
mov r0, r4
mov r2, #1
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r0, [r4]
sub r0, r0, #24
ldr r0, [r0]
add r0, r0, r4
ldr r5, [r0, #240]
cmp r5, #0
beq .LBB0_5
@ BB#1: @ %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit
ldrb r0, [r5, #28]
cmp r0, #0
beq .LBB0_3
@ BB#2:
ldrb r0, [r5, #39]
b .LBB0_4
.LBB0_3:
mov r0, r5
bl _ZNKSt5ctypeIcE13_M_widen_initEv
ldr r0, [r5]
mov r1, #10
ldr r2, [r0, #24]
mov r0, r5
mov lr, pc
mov pc, r2
.LBB0_4: @ %_ZNKSt5ctypeIcE5widenEc.exit
lsl r0, r0, #24
asr r1, r0, #24
mov r0, r4
bl _ZNSo3putEc
bl _ZNSo5flushEv
mov r0, #0
pop {r4, r5, lr}
mov pc, lr
.LBB0_5:
bl _ZSt16__throw_bad_castv
.align 2
@ BB#6:
Tuttavia, a dire il vero, questo non significa nulla, dato che l'I / O è comunque il collo di bottiglia. Volevo solo dimostrare che iostreamnon è più veloce perché è "sicuro da scrivere". La maggior parte delle implementazioni in C implementa i printfformati usando goto calcolato, quindi printfè il più veloce possibile, anche senza che il compilatore ne sia a conoscenza printf(non che non lo siano - alcuni compilatori possono ottimizzare printfin alcuni casi - la stringa costante che termina con \nè di solito ottimizzata per puts) .
Non so perché vorresti ereditare ostream, ma non mi interessa. È possibile FILEanche con .
class MyFile : public FILE {}
I veri elenchi di argomenti a lunghezza variabile non hanno sicurezza, ma non importa, poiché i compilatori C più diffusi possono rilevare problemi con la printfstringa di formato se si abilitano gli avvisi. In effetti, Clang può farlo senza abilitare gli avvisi.
$ cat safety.c
#include <stdio.h>
int main(void) {
printf("String: %s\n", 42);
return 0;
}
$ clang safety.c
safety.c:4:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
printf("String: %s\n", 42);
~~ ^~
%d
1 warning generated.
$ gcc -Wall safety.c
safety.c: In function ‘main’:
safety.c:4:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("String: %s\n", 42);
^
std::sort, che è in qualche modo sorprendentemente veloce rispetto a qsort(2 volte), a costo di dimensione eseguibile).
Dalle domande frequenti su C ++ :
[15.1] Perché dovrei usare al
<iostream>posto del tradizionale<cstdio>?Aumentare la sicurezza dei tipi, ridurre gli errori, consentire l'estensibilità e fornire l'ereditarietà.
printf()è probabilmente non rotto, edscanf()è forse vivibile nonostante sia soggetto a errori, tuttavia entrambi sono limitati rispetto a ciò che l'I / O C ++ può fare. I / O C ++ (usando<<e>>) è, rispetto a C (usandoprintf()escanf()):
- Più sicuro per i tipi: con
<iostream>, il tipo di oggetto che è I / O'd è noto staticamente dal compilatore. Al contrario,<cstdio>utilizza i campi "%" per capire i tipi in modo dinamico.- Meno soggetto a errori: con
<iostream>, non ci sono token "%" ridondanti che devono essere coerenti con gli oggetti reali che sono I / O. La rimozione della ridondanza rimuove una classe di errori.- Estensibile: il
<iostream>meccanismo C ++ consente I / O di nuovi tipi definiti dall'utente senza rompere il codice esistente. Immagina il caos se tutti aggiungessero simultaneamente nuovi campi "%" incompatibili aprintf()escanf()?!- Eredita: il
<iostream>meccanismo C ++ è costruito da classi reali comestd::ostreamestd::istream. A differenza<cstdio>di quelliFILE*, si tratta di classi reali e quindi ereditabili. Ciò significa che puoi avere altre cose definite dall'utente che sembrano e si comportano come flussi, ma che fanno qualsiasi cosa strana e meravigliosa tu voglia. Puoi usare automaticamente i miliardi di righe di codice I / O scritti da utenti che non conosci nemmeno e che non hanno bisogno di conoscere la tua classe "stream esteso".
D'altra parte, printfè significativamente più veloce, il che può giustificare l'utilizzo preferibilmente coutin casi molto specifici e limitati. Profili sempre per primo. (Vedi, ad esempio, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout /)
printf()dovrebbe anche essere estensibile. Vedi "ganci printf" su udrepper.livejournal.com/20948.html
printfnon ha tale capacità. I meccanismi di libreria non portatili non sono quasi allo stesso livello dell'estensibilità completamente standardizzata degli iostreams.
Le persone spesso affermano che printfè molto più veloce. Questo è in gran parte un mito. L'ho appena testato, con i seguenti risultati:
cout with only endl 1461.310252 ms
cout with only '\n' 343.080217 ms
printf with only '\n' 90.295948 ms
cout with string constant and endl 1892.975381 ms
cout with string constant and '\n' 416.123446 ms
printf with string constant and '\n' 472.073070 ms
cout with some stuff and endl 3496.489748 ms
cout with some stuff and '\n' 2638.272046 ms
printf with some stuff and '\n' 2520.318314 ms
Conclusione: se si desidera solo nuove righe, utilizzare printf; altrimenti, coutè quasi altrettanto veloce o persino più veloce. Maggiori dettagli possono essere trovati sul mio blog .
Per essere chiari, non sto cercando di dire che iostreamsono sempre meglio di printf; Sto solo cercando di dire che dovresti prendere una decisione informata sulla base di dati reali, non un'ipotesi selvaggia basata su un presupposto comune e fuorviante.
Aggiornamento: ecco il codice completo che ho usato per i test. Compilato con g++senza ulteriori opzioni (a parte -lrtper i tempi).
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
timespec d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
clock_gettime(CLOCK_REALTIME, &d_start);
}
~TimedSection() {
timespec end;
clock_gettime(CLOCK_REALTIME, &end);
double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
std::cerr << d_name << '\t' << std::fixed << duration << " ms\n";
}
};
int main() {
const int iters = 10000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
}
printf()e std::ostreamè che il primo genera tutti gli argomenti in una singola chiamata mentre std::ostreamincorre in una chiamata separata per ciascuno <<. Il test genera solo un argomento e una nuova riga, ecco perché non puoi vedere la differenza.
printfpotrebbe fare molte chiamate sotto le copertine per le funzioni di supporto per vari identificatori di formattazione ... che, o è una mostruosa funzione monolitica. E ancora, a causa dell'inline, non dovrebbe fare alcuna differenza in termini di velocità.
sprintfo fprintfe stringstreamo fstream.
E cito :
In termini di alto livello, le principali differenze sono la sicurezza dei tipi (cstdio non ce l'ha), le prestazioni (la maggior parte delle implementazioni di iostreams sono più lente di quelle cstdio) e l'estensibilità (iostreams consente target di output personalizzati e output senza interruzioni di tipi definiti dall'utente).
Una è una funzione che stampa su stdout. L'altro è un oggetto che fornisce diverse funzioni membro e sovraccarichi di operator<<quella stampa su stdout. Ci sono molte altre differenze che potrei enumerare, ma non sono sicuro di cosa stai cercando.
Per me, le vere differenze che mi farebbero andare per "cout" piuttosto che "printf" sono:
1) << L' operatore può essere sovraccarico per le mie lezioni.
2) Il flusso di output per cout può essere facilmente modificato in un file: (: copia incolla :)
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
streambuf* sbuf = cout.rdbuf();
cout.rdbuf(file.rdbuf());
cout << "This is sent to file" << endl;
cout.rdbuf(sbuf);
cout << "This is also sent to prompt" << endl;
return 0;
}
3) Trovo che cout sia più leggibile, specialmente quando abbiamo molti parametri.
Un problema con coutè le opzioni di formattazione. La formattazione dei dati (precisione, giustificazione, ecc.) printfÈ più semplice.
printfa un file anche sostituendolo con fprintf...
Due punti non menzionati altrimenti qui che trovo significativi:
1) couttrasporta molti bagagli se non si utilizza già la STL. Aggiunge oltre il doppio del codice al file oggetto di printf. Questo vale anche per string, e questa è la ragione principale per cui tendo a usare la mia libreria di stringhe.
2) coututilizza <<operatori sovraccarichi , che trovo sfortunato. Questo può aggiungere confusione se stai usando anche il<< operatore per lo scopo previsto (spostamento a sinistra). Personalmente non mi piace sovraccaricare gli operatori per scopi tangenziali per l'uso previsto.
In conclusione: userò cout (e string) se sto già usando l'STL. Altrimenti, tendo ad evitarlo.
Con i primitivi, probabilmente non importa del tutto quale usi. Dico dove diventa utile quando si desidera produrre oggetti complessi.
Ad esempio, se hai una lezione,
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// output with printf
printf("%i, %i, %i\n", s.a, s.b, s.c);
// output with cout
cout << s << endl;
return 0;
}
Ora, quanto sopra potrebbe non sembrare eccezionale, ma supponiamo che sia necessario emetterlo in più punti del codice. Non solo, diciamo che aggiungi un campo "int d". Con cout, devi cambiarlo solo una volta. Tuttavia, con printf, dovresti cambiarlo in molti posti e non solo, devi ricordare a te stesso quali produrre.
Detto questo, con cout, puoi ridurre un sacco di tempo speso con la manutenzione del tuo codice e non solo se riutilizzi l'oggetto "Something" in una nuova applicazione, non devi preoccuparti dell'output.
Ovviamente puoi scrivere "qualcosa" un po 'meglio per mantenere la manutenzione:
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
void print() const { printf("%i, %i, %i\n", a, b, c); }
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// Output with printf
s.print(); // Simple as well, isn't it?
// Output with cout
cout << s << endl;
return 0;
}
E un test un po 'esteso di cout vs. printf, ha aggiunto un test di' double ', se qualcuno vuole fare altri test (Visual Studio 2008, versione di rilascio dell'eseguibile):
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
//timespec d_start;
clock_t d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
//clock_gettime(CLOCK_REALTIME, &d_start);
d_start = clock();
}
~TimedSection() {
clock_t end;
//clock_gettime(CLOCK_REALTIME, &end);
end = clock();
double duration = /*1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
*/
(double) (end - d_start) / CLOCKS_PER_SEC;
std::cerr << d_name << '\t' << std::fixed << duration * 1000.0 << " ms\n";
}
};
int main() {
const int iters = 1000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
{
TimedSection s("cout with formatted double (width & precision once)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
std::cout.width(8);
for (int i = 0; i < iters; ++i)
std::cout << text << 8.315 << i << '\n';
}
{
TimedSection s("cout with formatted double (width & precision on each call)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
for (int i = 0; i < iters; ++i)
{ std::cout.width(8);
std::cout.precision(3);
std::cout << text << 8.315 << i << '\n';
}
}
{
TimedSection s("printf with formatted double");
for (int i = 0; i < iters; ++i)
printf("%8.3f%i\n", 8.315, i);
}
}
Il risultato è:
cout with only endl 6453.000000 ms
cout with only '\n' 125.000000 ms
printf with only '\n' 156.000000 ms
cout with string constant and endl 6937.000000 ms
cout with string constant and '\n' 1391.000000 ms
printf with string constant and '\n' 3391.000000 ms
cout with some stuff and endl 9672.000000 ms
cout with some stuff and '\n' 7296.000000 ms
printf with some stuff and '\n' 12235.000000 ms
cout with formatted double (width & precision once) 7906.000000 ms
cout with formatted double (width & precision on each call) 9141.000000 ms
printf with formatted double 3312.000000 ms
endlmolto meno efficiente di '\n'?
endlscarica il buffer e \nnon lo è, anche se non sono sicuro che questo sia definitivamente il motivo.
Vorrei sottolineare che se vuoi giocare con i thread in C ++, se lo usi coutpuoi ottenere risultati interessanti.
Considera questo codice:
#include <string>
#include <iostream>
#include <thread>
using namespace std;
void task(int taskNum, string msg) {
for (int i = 0; i < 5; ++i) {
cout << "#" << taskNum << ": " << msg << endl;
}
}
int main() {
thread t1(task, 1, "AAA");
thread t2(task, 2, "BBB");
t1.join();
t2.join();
return 0;
}
// g++ ./thread.cpp -o thread.out -ansi -pedantic -pthread -std=c++0x
Ora, l'output viene tutto mischiato. Può produrre anche risultati diversi, prova a eseguire più volte:
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
Puoi usare printfper farlo bene, oppure puoi usare mutex.
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
Divertiti!
threadnon fa impazzire l'output. Ho appena riprodotto e trovato entrambi xyze ABCnell'output. Non c'è stato un assalto b / n ABCcome ABABAB.
coutfunziona con i thread, ma so per certo che il codice che stai mostrando non è quello che hai usato per ottenere questi output. Il codice passa la stringa "ABC"per il thread 1 e "xyz"per il thread 2, ma l'output mostra AAAe BBB. Correggi, perché in questo momento è confuso.
cout<< "Hello";
printf("%s", "Hello");
Entrambi sono usati per stampare valori. Hanno una sintassi completamente diversa. C ++ ha entrambi, C ha solo printf.
Vorrei dire che la mancanza di estensibilità non printfè del tutto vera:
in C è vera. Ma in C non ci sono classi reali.
In C ++, è possibile sovraccaricare l'operatore di cast, quindi, sovraccaricando un char*operatore e usando printfcosì:
Foo bar;
...;
printf("%s",bar);
può essere possibile, se Foo sovraccarica l'operatore buono. O se hai fatto un buon metodo. In breve, printfè estensibile come coutper me.
Gli argomenti tecnici che posso vedere per i flussi C ++ (in generale ... non solo cout.) Sono:
Sicurezza rispetto ai tipi. (E, a proposito, se voglio stampare un singolo '\n'che usoputchar('\n') ... Non userò una bomba atomica per uccidere un insetto.).
Più semplice da imparare. (nessun parametro "complicato" da imparare, solo da usare <<e >>operatori)
Lavora nativamente con std::string(perché printfc'è std::string::c_str(), ma per scanf?)
Perché printfvedo:
Formattazione complessa più semplice o almeno più breve (in termini di caratteri scritti). Molto più leggibile, per me (questione di gusti immagino).
Migliore controllo di ciò che la funzione ha fatto (Restituisce quanti caratteri sono stati scritti e c'è il %nformattatore: "Niente di stampato. L'argomento deve essere un puntatore a un int firmato, dove è memorizzato il numero di caratteri scritti finora." (Da printf - Riferimento C ++ )
Migliori possibilità di debug. Per lo stesso motivo dell'ultimo argomento.
Le mie preferenze personali vanno a printf(e scanf) funzioni, principalmente perché amo le righe brevi e perché non penso che i problemi di tipo sulla stampa del testo siano davvero difficili da evitare. L'unica cosa che deploro con le funzioni in stile C è che std::stringnon è supportato. Dobbiamo passare attraverso un char*prima di darlo a printf(con il std::string::c_str()se vogliamo leggere, ma come scrivere?)
char*non verrà utilizzata.
char*vite e per quanto tempo e i pericoli definiti dall'utente cast impliciti.
Altre differenze: "printf" restituisce un valore intero (uguale al numero di caratteri stampati) e "cout" non restituisce nulla
E.
cout << "y = " << 7; non è atomico.
printf("%s = %d", "y", 7); è atomico.
cout esegue il controllo dei caratteri, printf no.
Non esiste un equivalente di iostream "% d"
coutnon restituisce nulla perché è un oggetto, non una funzione. operator<<restituisce qualcosa (normalmente il suo operando di sinistra, ma un valore falso in caso di errore). E in che senso la printfchiamata "atomica"?
printf("%s\n",7);
%sè?
printf % s deve avere un puntatore valido a una stringa terminata null. L'intervallo di memoria '7' (un puntatore) non è generalmente valido; un errore di segmentazione potrebbe essere fortunato. Su alcuni sistemi, '7' potrebbe stampare un sacco di immondizia su una console e dovresti guardarlo per un giorno prima che il programma si fermi. In altre parole, questa è una cosa negativa printf. Gli strumenti di analisi statica possono rilevare molti di questi problemi.
printfnon esegue il controllo dei caratteri, non ho mai usato un compilatore che non mi avvertisse degli errori di battitura con printf...
TL; DR: fai sempre le tue ricerche, per quanto riguarda le dimensioni del codice macchina generato , le prestazioni , la leggibilità e il tempo di codifica prima di fidarti dei commenti casuali online, incluso questo.
Non sono un esperto. Mi è appena capitato di sentire due colleghi che parlavano di come dovremmo evitare l'uso del C ++ nei sistemi embedded a causa di problemi di prestazioni. Bene, abbastanza interessante, ho fatto un benchmark basato su un vero compito di progetto.
Nel suddetto compito, abbiamo dovuto scrivere alcune configurazioni nella RAM. Qualcosa di simile a:
caffè =
zucchero caldo = nessuno
latte = petto
mac = AA: BB: CC: DD: EE: FF
Ecco i miei programmi di benchmark (Sì, so che OP ha chiesto di printf (), non di fprintf (). Cerca di catturare l'essenza e, comunque, il link di OP punta comunque a fprintf ().)
Programma C:
char coffee[10], sugar[10], milk[10];
unsigned char mac[6];
/* Initialize those things here. */
FILE * f = fopen("a.txt", "wt");
fprintf(f, "coffee=%s\nsugar=%s\nmilk=%s\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n", coffee, sugar, milk, mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);
fclose(f);
Programma C ++:
//Everything else is identical except:
std::ofstream f("a.txt", std::ios::out);
f << "coffee=" << coffee << "\n";
f << "sugar=" << sugar << "\n";
f << "milk=" << milk << "\n";
f << "mac=" << (int)mac[0] << ":"
<< (int)mac[1] << ":"
<< (int)mac[2] << ":"
<< (int)mac[3] << ":"
<< (int)mac[4] << ":"
<< (int)mac[5] << endl;
f.close();
Ho fatto del mio meglio per lucidarli prima di ripercorrerli entrambi 100.000 volte. Ecco i risultati:
Programma C:
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
Programma C ++:
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
Dimensione del file oggetto:
C - 2,092 bytes
C++ - 3,272 bytes
Conclusione: sulla mia piattaforma molto specifica , con un processore molto specifico , che esegue una versione molto specifica del kernel Linux , per eseguire un programma compilato con una versione molto specifica di GCC , al fine di svolgere un compito molto specifico , direi l'approccio C ++ è più adatto perché funziona in modo significativamente più veloce e offre una leggibilità molto migliore. D'altra parte, C offre un ingombro ridotto, a mio avviso, non significa quasi nulla perché la dimensione del programma non è una nostra preoccupazione.
Remeber, YMMV.
Non sono un programmatore, ma sono stato un ingegnere dei fattori umani. Penso che un linguaggio di programmazione dovrebbe essere facile da imparare, comprendere e usare, e questo richiede che abbia una struttura linguistica semplice e coerente. Sebbene tutte le lingue siano simboliche e quindi, in sostanza, arbitrarie, esistono convenzioni e seguirle rende la lingua più facile da imparare e usare.
Esistono un gran numero di funzioni in C ++ e altri linguaggi scritti come funzione (parametro), una sintassi che era originariamente utilizzata per le relazioni funzionali in matematica nell'era pre-computer. printf()segue questa sintassi e se gli autori di C ++ volessero creare un metodo logicamente diverso per leggere e scrivere file avrebbero potuto semplicemente creare una funzione diversa usando una sintassi simile.
Ovviamente in Python possiamo stampare usando anche abbastanza standard object.method sintassi , cioè variablename.print, poiché le variabili sono oggetti, ma in C ++ non lo sono.
Non mi piace la sintassi di Cout perché l'operatore << non segue alcuna regola. È un metodo o una funzione, ovvero accetta un parametro e fa qualcosa. Tuttavia è scritto come se fosse un operatore di confronto matematico. Questo è un approccio scadente dal punto di vista dei fattori umani.
printfè una funzione mentre coutè una variabile.
printfè una funzione, ma printf()è una funzione chiamata =)