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 ++ :
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 /)la source
printf()
est également censé être extensible. Voir "printf hooks" sur udrepper.livejournal.com/20948.htmlprintf
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: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 queprintf
; 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).la source
printf()
etstd::ostream
est que le premier produit tous les arguments en un seul appel alors qu'ilstd::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
oufprintf
etstringstream
oufstream
.Et je cite :
la source
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.la source
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 :)
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.la source
printf
à un fichier en le remplaçant parfprintf
...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 queprintf
. Cela est également vrai pourstring
, 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
(etstring
) si j'utilise déjà la STL. Sinon, j'ai tendance à l'éviter.la source
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,
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.
la source
Bien sûr, vous pouvez écrire "quelque chose" un peu mieux pour garder la maintenance:
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):
Le résultat est:
la source
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:
Maintenant, la sortie est mélangée. Il peut également donner des résultats différents, essayez de l'exécuter plusieurs fois:
Vous pouvez utiliser
printf
pour bien faire les choses, ou vous pouvez utilisermutex
.S'amuser!
la source
thread
ne rendent pas la sortie folle. Je viens de reproduire et de trouver à la foisxyz
etABC
dans la sortie. Il n'y avait pas de bangleries b / wABC
commeABABAB
.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 afficheAAA
etBBB
. Veuillez le corriger, car en ce moment, c'est déroutant.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.
la source
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 utiliserprintf
comme ceci: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 quecout
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'utiliseputchar('\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
(carprintf
il y en astd::string::c_str()
, mais pourscanf
?)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
(etscanf
), 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 cestd::string
n'est pas supporté. Nous devons passer par unchar*
avant de le donnerprintf
(avec lestd::string::c_str()
si nous voulons lire, mais comment écrire?)la source
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"
la source
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 choseprintf
. 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 avecprintf
...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:
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:
Programme C ++:
J'ai fait de mon mieux pour les polir avant de les boucler 100 000 fois. Voici les résultats:
Programme C:
Programme C ++:
Taille du fichier objet:
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.
la source
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.
la source
printf
est une fonction alors quecout
est une variable.la source
printf
est une fonction, maisprintf()
est un appel de fonction =)