Réponses:
Je suis surpris que tout le monde dans cette question affirme que std::cout
c'est bien mieux que printf
, même si la question demandait simplement des différences. Maintenant, il y a une différence - std::cout
c'est C ++, et printf
c'est C (cependant, vous pouvez l'utiliser en C ++, comme presque n'importe quoi d'autre de C). Maintenant, je vais être honnête ici; les deux printf
et std::cout
ont leurs avantages.
std::cout
est extensible. Je sais que les gens diront que printf
c'est également extensible, mais une telle extension n'est pas mentionnée dans la norme C (vous devrez donc utiliser des fonctionnalités non standard - mais il n'existe même pas de fonctionnalité non standard commune), et de telles extensions ne sont qu'une lettre (il est donc facile d'entrer en conflit avec un format déjà existant).
Contrairement à printf
, std::cout
dépend entièrement de la surcharge de l'opérateur, il n'y a donc aucun problème avec les formats personnalisés - tout ce que vous faites est de définir un sous-programme en prenant std::ostream
le premier argument et votre type en second. En tant que tel, il n'y a pas de problèmes d'espace de noms - tant que vous avez une classe (qui n'est pas limitée à un caractère), vous pouvez avoir du travailstd::ostream
surcharge de pour elle.
Cependant, je doute que beaucoup de gens voudraient étendre ostream
(pour être honnête, j'ai rarement vu de telles extensions, même si elles sont faciles à faire). Cependant, il est là si vous en avez besoin.
Comme il pourrait être facilement remarqué, à la fois printf
et std::cout
utiliser une syntaxe différente. printf
utilise la syntaxe de fonction standard en utilisant une chaîne de modèle et des listes d'arguments de longueur variable. En fait, printf
c'est une raison pour laquelle C en a - les printf
formats sont trop complexes pour être utilisables sans eux. Cependant, std::cout
utilise une API différente - l' operator <<
API qui se retourne.
Généralement, cela signifie que la version C sera plus courte, mais dans la plupart des cas, cela n'aura pas d'importance. La différence est notable lorsque vous imprimez de nombreux arguments. Si vous devez écrire quelque chose comme Error 2: File not found.
, en supposant le numéro d'erreur et que sa description est un espace réservé, le code ressemblerait à ceci. Les deux exemples fonctionnent de manière identique (enfin, en quelque sorte, std::endl
vide le tampon).
printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;
Bien que cela ne semble pas trop fou (c'est juste deux fois plus long), les choses deviennent plus folles lorsque vous formatez réellement des arguments, au lieu de simplement les imprimer. Par exemple, l'impression de quelque chose comme ça 0x0424
est tout simplement fou. Cela est dû au std::cout
mélange de l'état et des valeurs réelles. Je n'ai jamais vu un langage où quelque chose comme std::setfill
serait un type (autre que C ++, bien sûr). printf
sépare clairement les arguments et le type réel. Je préférerais vraiment en conserver la printf
version (même si elle a l'air un peu cryptique) par rapport à sa iostream
version (car elle contient trop de bruit).
printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;
C'est là que réside le véritable avantage du printf
mensonge. La printf
chaîne de format est bien ... une chaîne. Cela rend la traduction vraiment facile par rapport à un operator <<
abus de iostream
. En supposant que la gettext()
fonction traduit et que vous souhaitez afficher Error 2: File not found.
, le code pour obtenir la traduction de la chaîne de format précédemment affichée ressemblerait à ceci:
printf(gettext("Error %d: %s.\n"), id, errors[id]);
Supposons maintenant que nous traduisons en Fictionish, où le numéro d'erreur est après la description. La chaîne traduite ressemblerait %2$s oru %1$d.\n
. Maintenant, comment le faire en C ++? Eh bien, je n'en ai aucune idée. Je suppose que vous pouvez créer de fausses iostream
constructions printf
auxquelles vous pouvez passer gettext
, ou quelque chose, à des fins de traduction. Bien sûr, ce $
n'est pas la norme C, mais c'est tellement courant qu'il est sûr de l'utiliser à mon avis.
C a beaucoup de types entiers, tout comme C ++. std::cout
gère tous les types pour vous, tout en printf
nécessitant une syntaxe spécifique en fonction d'un type entier (il existe des types non entiers, mais le seul type non entier que vous utiliserez en pratique avec printf
est const char *
(la chaîne C, peut être obtenue en utilisant la to_c
méthode de std::string
)). Par exemple, pour imprimer size_t
, vous devez utiliser %zd
, tandis que vous int64_t
devrez utiliser %"PRId64"
. Les tableaux sont disponibles sur http://en.cppreference.com/w/cpp/io/c/fprintf et http://en.cppreference.com/w/cpp/types/integer .
\0
Parce qu'il printf
utilise des chaînes C par opposition aux chaînes C ++, il ne peut pas imprimer d'octet NUL sans astuces spécifiques. Dans certains cas, il est possible d'utiliser %c
avec '\0'
comme argument, bien que ce soit clairement un hack.
Mise à jour: Il s'avère que iostream
c'est si lent qu'il est généralement plus lent que votre disque dur (si vous redirigez votre programme vers un fichier). La désactivation de la synchronisation avec stdio
peut être utile si vous avez besoin de générer de nombreuses données. Si les performances sont un réel problème (par opposition à l'écriture de plusieurs lignes dans STDOUT), utilisez simplementprintf
.
Tout le monde pense qu'ils se soucient de la performance, mais personne ne se soucie de la mesurer. Ma réponse est que les E / S sont de toute façon un goulot d'étranglement, peu importe si vous utilisez printf
ou iostream
. Je pense que cela printf
pourrait être plus rapide d'un rapide coup d'œil à l'assemblage (compilé avec clang en utilisant l' -O3
option du compilateur). En supposant mon exemple d'erreur, l' printf
exemple fait beaucoup moins d'appels que l' cout
exemple. C'est int main
avec 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:
Vous pouvez facilement remarquer que deux chaînes et 2
(nombre) sont poussées comme printf
arguments. C'est à peu près ça; il n'y a rien d'autre. À titre de comparaison, cela est iostream
compilé pour l'assemblage. Non, il n'y a pas de doublure; chaque operator <<
appel unique signifie un autre appel avec un autre ensemble d'arguments.
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:
Cependant, pour être honnête, cela ne signifie rien, car les E / S sont de toute façon le goulot d'étranglement. Je voulais juste montrer que ce iostream
n'est pas plus rapide parce que c'est "type safe". La plupart des implémentations C implémentent des printf
formats utilisant goto calculé, donc printf
c'est aussi rapide que possible, même sans que le compilateur en soit conscient printf
(pas qu'ils ne le soient pas - certains compilateurs peuvent optimiser printf
dans certains cas - la chaîne constante se terminant par \n
est généralement optimisée pourputs
) .
Je ne sais pas pourquoi tu voudrais hériter ostream
, mais je m'en fiche. C'est possible avec FILE
aussi.
class MyFile : public FILE {}
Certes, les listes d'arguments de longueur variable n'ont aucune sécurité, mais cela n'a pas d'importance, car les compilateurs C populaires peuvent détecter des problèmes avec la printf
chaîne de format si vous activez les avertissements. En fait, Clang peut le faire sans activer les avertissements.
$ 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
, qui est en quelque sorte étonnamment rapide par rapport à qsort
(2 fois), à coût de la taille exécutable).
De la FAQ C ++ :
[15.1] Pourquoi devrais-je utiliser à la
<iostream>
place du traditionnel<cstdio>
?Augmentez la sécurité des types, réduisez les erreurs, permettez l'extensibilité et fournissez l'héritabilité.
printf()
n'est sans doute pas cassé, etscanf()
est peut-être habitable malgré le risque d'erreur, mais les deux sont limités en ce qui concerne ce que les E / S C ++ peuvent faire. Les E / S C ++ (en utilisant<<
et>>
) sont, par rapport à C (en utilisantprintf()
etscanf()
):
- Plus sûr pour
<iostream>
le type : Avec , le type d'objet étant I / O'd est connu statiquement par le compilateur. En revanche,<cstdio>
utilise les champs "%" pour déterminer les types de manière dynamique.- Moins sujet aux erreurs: avec
<iostream>
, il n'y a pas de jetons "%" redondants qui doivent être cohérents avec les objets réels qui sont I / O'd. La suppression de la redondance supprime une classe d'erreurs.- Extensible: Le
<iostream>
mécanisme C ++ permet aux nouveaux types définis par l'utilisateur d'être I / O'd sans casser le code existant. Imaginez le chaos si tout le monde ajoutait simultanément de nouveaux champs "%" incompatibles àprintf()
etscanf()
?!- Héritable: Le
<iostream>
mécanisme C ++ est construit à partir de classes réelles telles questd::ostream
etstd::istream
. Contrairement à<cstdio>
« sFILE*
, ce sont des classes réelles et , par conséquent héritable. Cela signifie que vous pouvez avoir d'autres choses définies par l'utilisateur qui ressemblent et agissent comme des flux, mais qui font tout ce que vous voulez d'étrange et de merveilleux. Vous pouvez automatiquement utiliser les millions de lignes de code d'E / S écrites par des utilisateurs que vous ne connaissez même pas, et ils n'ont pas besoin de connaître votre classe de "flux étendu".
D'autre part, printf
est beaucoup plus rapide, ce qui peut justifier l' utilisation de préférence à cout
en très cas spécifiques et limitées. Profilez toujours en premier. (Voir, par exemple, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout /)
printf()
est également censé être extensible. Voir "printf hooks" sur udrepper.livejournal.com/20948.html
printf
n'a pas une telle capacité. Les mécanismes de bibliothèque non portables ne sont guère au même niveau que l'extensibilité entièrement standardisée des flux ios.
Les gens prétendent souvent que printf
c'est beaucoup plus rapide. C'est en grande partie un mythe. Je viens de le tester, avec les résultats suivants:
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
Conclusion: si vous ne voulez que des retours à la ligne, utilisez printf
; sinon, cout
est presque aussi rapide, voire plus rapide. Plus de détails peuvent être trouvés sur mon blog .
Pour être clair, je n'essaie pas de dire que iostream
s valent toujours mieux que printf
; J'essaie simplement de dire que vous devriez prendre une décision éclairée basée sur des données réelles, et non une supposition sauvage basée sur une hypothèse commune et trompeuse.
Mise à jour: voici le code complet que j'ai utilisé pour les tests. Compilé g++
sans aucune option supplémentaire (sauf -lrt
pour le timing).
#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()
et std::ostream
est que le premier produit tous les arguments en un seul appel alors qu'il std::ostream
engendre un appel distinct pour chacun <<
. Le test ne produit qu'un seul argument et une nouvelle ligne, c'est pourquoi vous ne pouvez pas voir la différence.
printf
pourrait faire beaucoup d'appels sous les couvertures pour des fonctions d'assistance pour divers spécificateurs de formatage ... cela, ou c'est une fonction monolithique monstrueuse. Et encore une fois, en raison de la doublure, cela ne devrait pas du tout faire une différence de vitesse.
sprintf
ou fprintf
et stringstream
ou fstream
.
Et je cite :
En termes de haut niveau, les principales différences sont la sécurité des types (cstdio ne l'a pas), les performances (la plupart des implémentations iostreams sont plus lentes que celles cstdio) et l'extensibilité (iostreams permet des cibles de sortie personnalisées et une sortie transparente des types définis par l'utilisateur).
L'une est une fonction qui imprime sur stdout. L'autre est un objet qui fournit plusieurs fonctions membres et surcharges de operator<<
cette impression à stdout. Il y a beaucoup plus de différences que je pourrais énumérer, mais je ne suis pas sûr de ce que vous recherchez.
Pour moi, les vraies différences qui me feraient opter pour 'cout' plutôt que pour 'printf' sont:
1) << L' opérateur peut être surchargé pour mes classes.
2) Le flux de sortie pour cout peut être facilement changé en un fichier: (: copier coller :)
#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) Je trouve cout plus lisible, surtout quand on a beaucoup de paramètres.
Un problème avec cout
les options de formatage. Le formatage des données (précision, justification, etc.) printf
est plus simple.
printf
à un fichier en le remplaçant par fprintf
...
Deux points non mentionnés ici que je trouve importants:
1) cout
transporte beaucoup de bagages si vous n'utilisez pas déjà la STL. Il ajoute plus de deux fois plus de code à votre fichier objet que printf
. Cela est également vrai pour string
, et c'est la principale raison pour laquelle j'ai tendance à utiliser ma propre bibliothèque de chaînes.
2) cout
utilise des <<
opérateurs surchargés , ce que je trouve regrettable. Cela peut ajouter de la confusion si vous utilisez également le<<
opérateur aux fins prévues (décalage vers la gauche). Personnellement, je n'aime pas surcharger les opérateurs à des fins tangentielles à leur utilisation prévue.
Conclusion: je vais utiliser cout
(et string
) si j'utilise déjà la STL. Sinon, j'ai tendance à l'éviter.
Avec les primitives, peu importe celle que vous utilisez. Je dis où cela devient utile, c'est quand vous voulez sortir des objets complexes.
Par exemple, si vous avez une classe,
#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;
}
Maintenant, ce qui précède peut ne pas sembler génial, mais supposons que vous deviez le produire à plusieurs endroits dans votre code. Non seulement cela, disons que vous ajoutez un champ "int d". Avec cout, vous n'avez qu'à le changer en une seule fois. Cependant, avec printf, vous devrez le changer dans peut-être beaucoup d'endroits et non seulement cela, vous devez vous rappeler ceux à sortir.
Cela dit, avec cout, vous pouvez réduire beaucoup de temps passé à la maintenance de votre code et pas seulement si vous réutilisez l'objet "Quelque chose" dans une nouvelle application, vous n'avez pas vraiment à vous soucier de la sortie.
Bien sûr, vous pouvez écrire "quelque chose" un peu mieux pour garder la maintenance:
#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;
}
Et un test un peu étendu de cout vs printf, a ajouté un test de 'double', si quelqu'un veut faire plus de tests (Visual Studio 2008, version finale de l'exécutable):
#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);
}
}
Le résultat est:
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
ce tellement moins efficace que '\n'
?
endl
vide le tampon, et \n
non, bien que je ne sois pas sûr que ce soit définitivement la raison.
Je voudrais souligner que si vous voulez jouer avec des threads en C ++, si vous utilisez, cout
vous pouvez obtenir des résultats intéressants.
Considérez ce code:
#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
Maintenant, la sortie est mélangée. Il peut également donner des résultats différents, essayez de l'exécuter plusieurs fois:
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
Vous pouvez utiliser printf
pour bien faire les choses, ou vous pouvez utiliser mutex
.
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
S'amuser!
thread
ne rendent pas la sortie folle. Je viens de reproduire et de trouver à la fois xyz
et ABC
dans la sortie. Il n'y avait pas de bangleries b / w ABC
comme ABABAB
.
cout
fonctionne les threads, mais je suis sûr que le code que vous affichez n'est pas celui que vous avez utilisé pour obtenir ces sorties. Votre code passe la chaîne "ABC"
pour le thread 1 et "xyz"
pour le thread 2, mais votre sortie affiche AAA
et BBB
. Veuillez le corriger, car en ce moment, c'est déroutant.
cout<< "Hello";
printf("%s", "Hello");
Les deux sont utilisés pour imprimer des valeurs. Ils ont une syntaxe complètement différente. C ++ a les deux, C n'a que printf.
Je voudrais dire que le manque d'extensibilité de printf
n'est pas entièrement vrai:
en C, c'est vrai. Mais en C, il n'y a pas de vraies classes.
En C ++, il est possible de surcharger l'opérateur cast, donc, surcharger un char*
opérateur et utiliser printf
comme ceci:
Foo bar;
...;
printf("%s",bar);
peut être possible, si Foo surcharge le bon opérateur. Ou si vous avez fait une bonne méthode. Bref, printf
c'est aussi extensible que cout
pour moi.
L'argument technique que je peux voir pour les flux C ++ (en général ... pas seulement cout.) Sont:
Sécurité de la typographie. (Et, au fait, si je veux imprimer un seul '\n'
que j'utilise putchar('\n')
... je n'utiliserai pas de bombe atomique pour tuer un insecte.).
Plus simple à apprendre. (pas de paramètres "compliqués" à apprendre, juste à utiliser <<
et >>
opérateurs)
Travaillez nativement avec std::string
(car printf
il y en a std::string::c_str()
, mais pour scanf
?)
Car printf
je vois:
Mise en forme complexe plus facile ou au moins plus courte (en termes de caractères écrits). Beaucoup plus lisible, pour moi (question de goût je suppose).
Meilleur contrôle de ce que la fonction a fait (Renvoyez le nombre de caractères écrits et le %n
formateur: "Rien imprimé. L'argument doit être un pointeur vers un entier signé, où le nombre de caractères écrits jusqu'ici est stocké." ( Tiré de printf - Référence C ++ )
Meilleures possibilités de débogage. Pour la même raison que le dernier argument.
Mes préférences personnelles vont aux fonctions printf
(et scanf
), principalement parce que j'aime les lignes courtes et parce que je ne pense pas que les problèmes de frappe sur l'impression de texte soient vraiment difficiles à éviter. La seule chose que je déplore avec les fonctions de style C, c'est que ce std::string
n'est pas supporté. Nous devons passer par un char*
avant de le donner printf
(avec le std::string::c_str()
si nous voulons lire, mais comment écrire?)
char*
ne sera pas utilisée.
char*
vivent et pour combien de temps, et les dangers de la définition par l'utilisateur lancements implicites.
Plus de différences: "printf" renvoie une valeur entière (égale au nombre de caractères imprimés) et "cout" ne renvoie rien
Et.
cout << "y = " << 7;
n'est pas atomique.
printf("%s = %d", "y", 7);
est atomique.
cout effectue la vérification typographique, printf non.
Il n'y a pas d'équivalent iostream de "% d"
cout
ne renvoie rien car c'est un objet, pas une fonction. operator<<
renvoie quelque chose (normalement son opérande gauche, mais une valeur fausse s'il y a une erreur). Et dans quel sens est l' printf
appel "atomique"?
printf("%s\n",7);
%s
est ?
printf
% s doit avoir un pointeur valide vers une chaîne terminée par null. La plage de mémoire «7» (un pointeur) n'est généralement pas valide; un défaut de segmentation pourrait être chanceux. Sur certains systèmes, «7» peut imprimer beaucoup de déchets sur une console et vous devrez le regarder pendant une journée avant l'arrêt du programme. En d'autres termes, c'est une mauvaise chose printf
. Les outils d'analyse statique peuvent détecter bon nombre de ces problèmes.
printf
ne fasse pas de vérification typographique, je n'ai jamais utilisé de compilateur qui ne m'avertisse pas d'erreurs de type avec printf
...
TL; DR: faites toujours vos propres recherches en ce qui concerne la taille du code machine généré , les performances , lisibilité et le temps de codage avant de faire confiance à des commentaires aléatoires en ligne, y compris celui-ci.
Je ne suis pas un expert. Je viens d'entendre deux collègues parler de la façon dont nous devrions éviter d'utiliser C ++ dans les systèmes embarqués en raison de problèmes de performances. Eh bien, assez intéressant, j'ai fait un benchmark basé sur une vraie tâche de projet.
Dans cette tâche, nous avons dû écrire une configuration sur la RAM. Quelque chose comme:
café =
sucre chaud = aucun
lait = macarine de poitrine
= AA: BB: CC: DD: EE: FF
Voici mes programmes de référence (Oui, je sais que OP a posé des questions sur printf (), pas sur fprintf (). Essayez de capturer l'essence et, en passant, le lien d'OP pointe vers fprintf () de toute façon.)
Programme 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);
Programme 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();
J'ai fait de mon mieux pour les polir avant de les boucler 100 000 fois. Voici les résultats:
Programme C:
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
Programme C ++:
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
Taille du fichier objet:
C - 2,092 bytes
C++ - 3,272 bytes
Conclusion: Sur ma plateforme très spécifique , avec un processeur très spécifique , exécutant une version très spécifique du noyau Linux , pour exécuter un programme qui est compilé avec une version très spécifique de GCC , afin d'accomplir une tâche très spécifique , je dirais l'approche C ++ est plus appropriée car elle s'exécute beaucoup plus rapidement et offre une bien meilleure lisibilité. D'un autre côté, C offre une petite empreinte, à mon avis, ne signifie presque rien parce que la taille du programme n'est pas notre préoccupation.
Remeber, YMMV.
Je ne suis pas programmeur, mais j'ai été ingénieur en facteurs humains. Je pense qu'un langage de programmation devrait être facile à apprendre, à comprendre et à utiliser, ce qui nécessite qu'il ait une structure linguistique simple et cohérente. Bien que toutes les langues soient symboliques et donc, à la base, arbitraires, il existe des conventions et les suivre facilite l'apprentissage et l'utilisation de la langue.
Il existe un grand nombre de fonctions en C ++ et dans d'autres langages écrits en tant que fonction (paramètre), une syntaxe qui était à l'origine utilisée pour les relations fonctionnelles en mathématiques à l'ère pré-informatique. printf()
suit cette syntaxe et si les auteurs de C ++ voulaient créer une méthode logiquement différente pour lire et écrire des fichiers, ils auraient pu simplement créer une fonction différente en utilisant une syntaxe similaire.
En Python, nous pouvons bien sûr imprimer en utilisant également object.method
syntaxe , c'est-à-dire variablename.print, car les variables sont des objets, mais en C ++, elles ne le sont pas.
Je n'aime pas la syntaxe cout car l'opérateur << ne suit aucune règle. C'est une méthode ou une fonction, c'est-à-dire qu'elle prend un paramètre et y fait quelque chose. Cependant, il est écrit comme s'il s'agissait d'un opérateur de comparaison mathématique. Il s'agit d'une mauvaise approche du point de vue des facteurs humains.
printf
est une fonction alors que cout
est une variable.
printf
est une fonction, mais printf()
est un appel de fonction =)