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 printf
e std::cout
hanno 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::cout
dipende completamente dal sovraccarico dell'operatore, quindi non ci sono problemi con i formati personalizzati: tutto ciò che devi fare è definire una subroutine std::ostream
come 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::ostream
sovraccarico 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 printf
e std::cout
utilizzare sintassi diversa. printf
usa 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 printf
formati sono troppo complessi per essere utilizzabili senza di essi. Tuttavia, std::cout
utilizza 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::endl
effettivamente 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::cout
miscelazione dello stato e dei valori effettivi. Non ho mai visto un linguaggio in cui qualcosa del genere std::setfill
sarebbe un tipo (diverso dal C ++, ovviamente). printf
separa chiaramente argomenti e tipo reale. Preferirei davvero mantenerne la printf
versione (anche se sembra un po 'criptica) rispetto alla iostream
versione 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 printf
bugie. La printf
stringa 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 iostream
quali costrutti printf
puoi 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::cout
gestisce tutti i tipi per te, mentre printf
richiede 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_c
metodo di std::string
)). Ad esempio, per stampare size_t
, è necessario utilizzare %zd
, mentre int64_t
richiederà 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 .
\0
Poiché printf
utilizza le stringhe C anziché le stringhe C ++, non può stampare byte NUL senza trucchi specifici. In alcuni casi è possibile utilizzare %c
con '\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 stdio
può 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 printf
o iostream
. Penso che printf
potrebbe essere più veloce da una rapida occhiata in assembly (compilato con clang usando l' -O3
opzione del compilatore). Supponendo il mio esempio di errore, l' printf
esempio fa meno chiamate rispetto cout
all'esempio. Questo è int main
con 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 printf
argomenti. Questo è tutto; non c'è nient'altro. Per confronto, questo viene iostream
compilato 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 iostream
non è più veloce perché è "sicuro da scrivere". La maggior parte delle implementazioni in C implementa i printf
formati 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 printf
in 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 FILE
anche 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 printf
stringa 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::ostream
estd::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 cout
in 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
printf
non 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 iostream
sono 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 -lrt
per 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::ostream
incorre in una chiamata separata per ciascuno <<
. Il test genera solo un argomento e una nuova riga, ecco perché non puoi vedere la differenza.
printf
potrebbe 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à.
sprintf
o fprintf
e stringstream
o 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.
printf
a un file anche sostituendolo con fprintf
...
Due punti non menzionati altrimenti qui che trovo significativi:
1) cout
trasporta 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) cout
utilizza <<
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
endl
molto meno efficiente di '\n'
?
endl
scarica il buffer e \n
non 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 cout
puoi 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 printf
per 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!
thread
non fa impazzire l'output. Ho appena riprodotto e trovato entrambi xyz
e ABC
nell'output. Non c'è stato un assalto b / n ABC
come ABABAB
.
cout
funziona 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 AAA
e 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 printf
così:
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 cout
per 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é printf
c'è std::string::c_str()
, ma per scanf
?)
Perché printf
vedo:
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 %n
formattatore: "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::string
non è 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"
cout
non 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 printf
chiamata "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.
printf
non 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 =)