‘printf’ vs ‘cout’ en C ++

Quelle est la différence entre printf() et cout en C ++?

    Je suis surpris que tout le monde dans cette question prétend que std::cout est bien meilleur que printf , même si la question demandait simplement des différences. Maintenant, il y a une différence – std::cout est C ++ et printf est C (cependant, vous pouvez l’utiliser en C ++, comme presque n’importe quoi d’autre en C). Maintenant, je serai honnête ici; printf et std::cout ont tous deux leurs avantages.

    Différences réelles

    Extensibilité

    std::cout est extensible. Je sais que les gens diront que printf est extensible aussi, mais une telle extension n’est pas mentionnée dans le standard C (vous devrez donc utiliser des fonctionnalités non standard – mais pas même des fonctionnalités non standard communes), et ces extensions ne font qu’un. 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 pas de problème avec les formats personnalisés – tout ce que vous faites est de définir un sous-programme prenant std::ostream comme premier argument et votre type comme 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 une surcharge de travail std::ostream .

    Cependant, je doute que beaucoup de gens veuillent étendre ostream (pour être honnête, j’ai rarement vu de telles extensions, même si elles sont faciles à faire). Cependant, c’est ici si vous en avez besoin.

    Syntaxe

    Comme cela peut être facilement remarqué, printf et std::cout utilisent une syntaxe différente. printf utilise une syntaxe de fonction standard à l’aide d’une liste de motifs et de listes d’arguments de longueur variable. En fait, printf est la raison pour laquelle C les a – les formats printf sont trop complexes pour être utilisables sans eux. Cependant, std::cout utilise une API différente – l’API d’ operator << qui renvoie elle-même.

    En général, cela signifie que la version C sera plus courte, mais dans la plupart des cas, cela n'aura aucune 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 un numéro d'erreur et sa description est un espace réservé, le code ressemblerait à ceci. Les deux exemples fonctionnent de manière identique (en quelque sorte, std::endl videra 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 (il est juste deux fois plus long), les choses deviennent plus folles lorsque vous formatez des arguments, au lieu de les imprimer. Par exemple, l'impression de quelque chose comme 0x0424 est tout simplement dingue. Ceci est dû au fait que std::cout mélange les valeurs d'état et les 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 version printf (même si cela semble un peu cryptique) par rapport à la version iostream (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; 

    Traduction

    C'est là que réside le véritable avantage de printf . La printf format printf est bien ... une chaîne. Cela le rend vraiment facile à traduire, comparé aux operator << abus d' iostream . En supposant que la fonction gettext() traduit et que vous souhaitez afficher l' 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]); 

    Maintenant, supposons que nous traduisions 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 faux iostream qui construit printf que vous pouvez transmettre à gettext , ou quelque chose, à des fins de traduction. Bien sûr, $ n'est pas la norme C, mais c'est tellement courant qu'il est sûr de l'utiliser à mon avis.

    Ne pas avoir à mémoriser / rechercher une syntaxe de type entier spécifique

    C a beaucoup de types entiers, tout comme C ++. std::cout gère tous les types pour vous, tandis que printf requirejs une syntaxe spécifique en fonction d'un type d'entier (il existe des types non entiers, mais le seul type non-entier que vous utiliserez en pratique avec printf est const char * (chaîne C, peut être obtenu en utilisant la méthode to_c de std::ssortingng )). Par exemple, pour imprimer size_t , vous devez utiliser %zd , alors que int64_t nécessitera d'utiliser %"PRId64" . Les tableaux sont disponibles à l' adresse http://en.cppreference.com/w/cpp/io/c/fprintf et http://en.cppreference.com/w/cpp/types/integer .

    Vous ne pouvez pas imprimer l'octet NUL, \0

    Comme printf utilise des chaînes C par opposition aux chaînes C ++, il ne peut pas imprimer l'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.

    Différences dont personne ne se soucie

    Performance

    Mise à jour: Il s'avère que iostream 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 devez générer beaucoup de données. Si la performance est un réel problème (par opposition à l'écriture de plusieurs lignes dans STDOUT), utilisez simplement printf .

    Tout le monde pense qu'ils se soucient de la performance, mais personne ne se soucie de le 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 printf pourrait être plus rapide à partir d'un rapide aperçu de l'assemblage (compilé avec clang en utilisant l'option du compilateur -O3 ). En supposant que mon exemple d'erreur, exemple printf fait beaucoup moins d'appels que l'exemple de cout . Ceci 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 en tant qu'arguments printf . C'est à peu près ça; il n'y a rien d'autre. Pour comparaison, c'est iostream compilé pour l'assemblage. Non, il n'y a pas d'inlining; chaque operator << appel 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 iostream n'est pas plus rapide parce que c'est "type safe". La plupart des implémentations C implémentent les formats printf en utilisant un goto calculé, de sorte que printf est aussi rapide que possible, même sans que le compilateur soit au courant de printf (certains compilateurs peuvent optimiser printf dans certains cas - chaîne constante se terminant par \n est généralement optimisé pour les puts ).

    Héritage

    Je ne sais pas pourquoi vous voudriez hériter de ostream , mais je m'en fiche. C'est possible avec FILE aussi.

     class MyFile : public FILE {} 

    Type de sécurité

    Certes, les listes d'arguments de longueur variable ne sont pas sûres, mais cela n'a pas d'importance, car les compilateurs C peuvent détecter les problèmes avec la printf format printf si vous activez les avertissements. En fait, Clang peut le faire sans activer les avertissements.

     $ cat safety.c #include  int main(void) { printf("Ssortingng: %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("Ssortingng: %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("Ssortingng: %s\n", 42); ^ 

    De la FAQ C ++ :

    [15.1] Pourquoi devrais-je utiliser au lieu du traditionnel?

    Augmentez la sécurité de type, réduisez les erreurs, autorisez l’extensibilité et apportez l’inheritance.

    printf() n’est pas cassé et que scanf() est peut-être habitable même s’il est sujet aux erreurs, mais les deux sont limités par rapport à ce que les E / S C ++ peuvent faire. C ++ I / O (en utilisant << et >> ) est, par rapport à C (en utilisant printf() et scanf() ):

    • Plus de type-safe: Avec , le type d'object I / O'd est connu statiquement par le compilateur. En revanche, utilise les champs "%" pour déterminer les types de manière dynamic.
    • Moins sujettes aux erreurs: Avec , il n'y a pas de jeton "%" redondant qui doit être cohérent avec les objects réels étant I / O'd. La suppression de la redondance supprime une classe d'erreurs.
    • Extensible: Le 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() et scanf() ?!
    • Inheritable: Le mécanisme C ++ est construit à partir de classes réelles telles que std::ostream et std::istream . Contrairement au FILE* , ce sont des classes réelles et donc héritables. Cela signifie que vous pouvez avoir d’autres éléments définis par l’utilisateur qui ressemblent à des stream, mais qui agissent comme vous le souhaitez. Vous obtenez automatiquement d'utiliser les milliards de lignes de code d'E / S écrites par les utilisateurs que vous ne connaissez même pas, et ils n'ont pas besoin de connaître votre classe "stream étendu".

    D'autre part, printf est nettement plus rapide, ce qui peut justifier de l'utiliser de préférence à cout dans des cas très spécifiques et limités. Toujours profiler en premier. (Voir, par exemple, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout /)

    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 de cstdio) et l’extensibilité

    Les gens prétendent souvent que printf 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 ssortingng constant and endl 1892.975381 ms cout with ssortingng constant and '\n' 416.123446 ms printf with ssortingng 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 nouvelles lignes, 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 les iostream sont toujours meilleurs 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 sur une hypothèse fausse basée sur des hypothèses courantes et trompeuses.

    Mise à jour: voici le code complet que j’ai utilisé pour les tests. Compilé avec g++ sans options supplémentaires (sauf -lrt pour le timing).

     #include  #include  #include  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); } } 

    L’une est une fonction qui imprime à la sortie standard. L’autre est un object qui fournit plusieurs fonctions membres et des surcharges d’ operator<< qui impriment à la sortie standard. 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 «cout» plutôt que «printf» sont:

    1) << L’ opérateur peut être surchargé pour mes cours.

    2) Le stream de sortie pour cout peut être facilement changé en fichier: (: copier coller 🙂

     #include  #include  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 lorsque nous avons beaucoup de parameters.

    Un problème avec cout est les options de formatage. Le formatage des données (précision, justification, etc.) dans printf est plus facile.

    Deux points non mentionnés ici que je trouve importants:

    1) cout porte beaucoup de bagages si vous n’utilisez pas déjà la STL. Il ajoute deux fois plus de code à votre fichier object que printf . Ceci est également vrai pour ssortingng , et c’est la raison principale 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 dommage. Cela peut créer une certaine confusion si vous utilisez aussi l’opérateur << à ses fins (décalage à gauche). Personnellement, je n'aime pas surcharger les opérateurs à des fins tangentielles.

    Bottom line: J'utiliserai cout (et ssortingng ) si j'utilise déjà la STL. Sinon, j'ai tendance à l'éviter.

    Avec les primitives, peu importe lequel vous utilisez. Je dis que c’est utile lorsque vous voulez sortir des objects complexes.

    Par exemple, si vous avez une classe,

     #include  #include  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 << sa << ", " << sb << ", " << sc; return o; } int main(void) { Something s(3, 2, 1); // output with printf printf("%i, %i, %i\n", sa, sb, sc); // output with cout cout << s << endl; return 0; } 

    Maintenant, ce qui précède peut ne pas sembler très intéressant, mais supposons que vous ayez à le sortir à plusieurs endroits dans votre code. Non seulement cela, disons que vous ajoutez un champ "int d". Avec cout, il suffit de le changer en un seul endroit. Cependant, avec printf, vous devrez le changer dans de nombreux endroits, et pas seulement cela, vous devez vous rappeler lesquels.

    Cela dit, avec cout, vous pouvez réduire beaucoup de temps consacré à la maintenance de votre code et pas seulement si vous réutilisez l'object "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 maintenir la maintenance:

     #include  #include  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 << sa << ", " << sb << ", " << sc; 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 plus long de cout par rapport à printf, a ajouté un test de «double», si quelqu'un veut faire plus de tests (Visual Studio 2008, version de l'exécutable):

     #include  #include  #include  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 ssortingng constant and endl 6937.000000 ms cout with ssortingng constant and '\n' 1391.000000 ms printf with ssortingng 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 

    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  #include  #include  using namespace std; void task(int taskNum, ssortingng 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, le résultat est tout mélangé. Il peut aussi donner des résultats différents, essayez d’exécuter plusieurs fois:

     ##12:: ABABAB ##12:: ABABAB ##12:: ABABAB ##12:: ABABAB ##12:: ABABAB 

    Vous pouvez utiliser printf pour le faire correctement ou utiliser mutex .

     #1: AAA #2: BBB #1: AAA #2: BBB #1: AAA #2: BBB #1: AAA #2: BBB #1: AAA #2: BBB 

    S'amuser!

     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 tout à fait vrai:
    En C, c’est vrai. Mais en C, il n’y a pas de classes réelles.
    En C ++, il est possible de surcharger l’opérateur cast, en surchargeant un opérateur char* et en utilisant 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. En bref, printf est aussi extensible que cout pour moi.

    L’argument technique que je peux voir pour les stream C ++ (en général … pas seulement cout) est:

    • La sécurité. (Et au fait, si je veux imprimer un seul '\n' j’utilise putchar('\n') … je n’utiliserai pas de bombe atomique pour tuer un insecte.)

    • Plus simple à apprendre (pas de parameters “compliqués” à apprendre, juste pour utiliser les opérateurs << et >> )

    • Travaillez en natif avec std::ssortingng (pour printf il y a std::ssortingng::c_str() , mais pour scanf ?)

    Pour printf je vois:

    • Un formatage plus simple, ou du moins plus court (en terme de caractères écrits). Beaucoup plus lisible, pour moi (question de goût je suppose).

    • Un meilleur contrôle de ce que la fonction a fait (Renvoyer combien de caractères sont écrits et il y a le formateur %n : "Rien imprimé. L'argument doit être un pointeur sur un int signé, où le nombre de caractères écrits jusqu'ici est stocké." à partir de printf - Référence C ++ )

    • De 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 type sur l'impression soient très difficiles à éviter. La seule chose que je déplore avec les fonctions de style C est que std::ssortingng n'est pas supporté. Nous devons passer par un caractère char* avant de le donner à printf (avec le std::ssortingng::c_str() si nous voulons lire, mais comment écrire?)

    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 une vérification de type, printf ne le fait pas.

    Il n'y a pas d'équivalent iostream de "% d"

    TL;DR: Always do your own research, in regard of generated machine code size , performance , readability and coding time before trusting random comments online, including this one.

    I’m no expert. I just happened to overhear two co-workers talking about how we should avoid using C++ in embedded systems because of performance issues. Well, interesting enough, I did a benchmark based on a real project task.

    In said task, we had to write some config to RAM. Quelque chose comme:

    coffee=hot
    sugar=none
    milk=breast
    mac=AA:BB:CC:DD:EE:FF

    Here’s my benchmark programs (Yes, I know OP asked about printf(), not fprintf(). Try to capture the essence and by the way, OP’s link points to fprintf() anyway.)

    C program:

     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); 

    C++ program:

     //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(); 

    I did my best to polish them before I looped them both 100,000 times. Voici les résultats:

    C program:

     real 0m 8.01s user 0m 2.37s sys 0m 5.58s 

    C++ program:

     real 0m 6.07s user 0m 3.18s sys 0m 2.84s 

    Object file size:

     C - 2,092 bytes C++ - 3,272 bytes 

    Conclusion: On my very specific platform , with a very specific processor , running a very specific version of Linux kernel , to run a program which is comstackd with a very specific version of GCC , in order to accomplish a very specific task , I would say the C++ approach is more suitable because it runs significantly faster and provide much better readability. On the other hand, C offers small footprint, in my opinion, means nearly nothing because program size is not of our concern.

    Remeber, YMMV.

    I’m not a programmer, but I have been a human factors engineer. I feel a programming language should be easy to learn, understand and use, and this requires that it have a simple and consistent linguistic structure. Although all the languages is symbolic and thus, at its core, arbitrary, there are conventions and following them makes the language easier to learn and use.

    There are a vast number of functions in C++ and other languages written as function(parameter), a syntax that was originally used for functional relationships in mathematics in the pre-computer era. printf() follows this syntax and if the writers of C++ wanted to create any logically different method for reading and writing files they could have simply created a different function using a similar syntax.

    In Python we of course can print using the also fairly standard object.method syntax, ie variablename.print, since variables are objects, but in C++ they are not.

    I’m not fond of the cout syntax because the << operator does not follow any rules. It is a method or function, ie it takes a parameter and does something to it. However it is written as though it were a mathematical comparison operator. This is a poor approach from a human factors standpoint.

    printf is a function whereas cout is a variable.