Adaptabilité
Toute tentative de printf
un non-POD entraîne un comportement non défini :
struct Foo {
virtual ~Foo() {}
operator float() const { return 0.f; }
};
printf ("%f", Foo());
std::string foo;
printf ("%s", foo);
Les appels printf ci-dessus produisent un comportement non défini. Votre compilateur peut en effet vous avertir, mais ces avertissements ne sont pas requis par les normes et ne sont pas possibles pour les chaînes de format connues uniquement au moment de l'exécution.
IO-Streams :
std::cout << Foo();
std::string foo;
std::cout << foo;
Jugez vous-même.
Extensibilité
struct Person {
string first_name;
string second_name;
};
std::ostream& operator<< (std::ostream &os, Person const& p) {
return os << p.first_name << ", " << p.second_name;
}
cout << p;
cout << p;
some_file << p;
C :
// inline everywhere
printf ("%s, %s", p.first_name, p.second_name);
printf ("%s, %s", p.first_name, p.second_name);
fprintf (some_file, "%s, %s", p.first_name, p.second_name);
ou :
// re-usable (not common in my experience)
int person_fprint(FILE *f, const Person *p) {
return fprintf(f, "%s, %s", p->first_name, p->second_name);
}
int person_print(const Person *p) {
return person_fprint(stdout, p);
}
Person p;
....
person_print(&p);
Notez que vous devez prendre soin d'utiliser les bons arguments/signatures d'appel en C (ex. person_fprint(stderr, ...
, person_fprint(myfile, ...
), alors qu'en C++, le " FILE
-argument" est automatiquement "dérivé" de l'expression. Un équivalent plus exact de cette dérivation est en fait plus proche de ceci :
FILE *fout = stdout;
...
fprintf(fout, "Hello World!\n");
person_fprint(fout, ...);
fprintf(fout, "\n");
I18N
Nous réutilisons notre définition de la personne :
~~cout << boost::format("Hello %1%") % p;
cout << boost::format("Na %1%, sei gegrüßt!") % p;
printf ("Hello %1$s, %2$s", p.first_name.c_str(), p.second_name.c_str());
printf ("Na %1$s, %2$s, sei gegrüßt!",
p.first_name.c_str(), p.second_name.c_str());~~
Jugez vous-même.
Je trouve cela moins pertinent à partir d'aujourd'hui (2017). Peut-être que c'est juste une intuition, mais I18N n'est pas quelque chose qui est fait sur une base quotidienne par votre programmeur C ou C++ moyen. De plus, c'est une douleur dans l'a...natomie de toute façon.
Performance
- Avez-vous mesuré l'importance réelle des performances de printf ? Vos applications goulot d'étranglement sont-elles sérieusement si paresseuses que la sortie des résultats de calcul constitue un goulot d'étranglement ? Êtes-vous sûr d'avoir besoin de C++ ?
- La pénalité de performance redoutée est destinée à satisfaire ceux d'entre vous qui veulent utiliser un mélange de printf et de cout. C'est une fonctionnalité, pas un bug !
Si vous utilisez systématiquement iostreams, vous pouvez
std::ios::sync_with_stdio(false);
et bénéficier d'un temps d'exécution égal avec un bon compilateur :
#include <cstdio>
#include <iostream>
#include <ctime>
#include <fstream>
void ios_test (int n) {
for (int i=0; i<n; ++i) {
std::cout << "foobarfrob" << i;
}
}
void c_test (int n) {
for (int i=0; i<n; ++i) {
printf ("foobarfrob%d", i);
}
}
int main () {
const clock_t a_start = clock();
ios_test (10024*1024);
const double a = (clock() - a_start) / double(CLOCKS_PER_SEC);
const clock_t p_start = clock();
c_test (10024*1024);
const double p = (clock() - p_start) / double(CLOCKS_PER_SEC);
std::ios::sync_with_stdio(false);
const clock_t b_start = clock();
ios_test (10024*1024);
const double b = (clock() - b_start) / double(CLOCKS_PER_SEC);
std::ofstream res ("RESULTS");
res << "C ..............: " << p << " sec\n"
<< "C++, sync with C: " << a << " sec\n"
<< "C++, non-sync ..: " << b << " sec\n";
}
Résultats ( g++ -O3 synced-unsynced-printf.cc
, ./a.out > /dev/null
, cat RESULTS
) :
C ..............: 1.1 sec
C++, sync with C: 1.76 sec
C++, non-sync ..: 1.01 sec
Jugez ... vous-même.
Non. Vous ne m'interdirez pas mon printf.
Vous pouvez créer un printf sûr pour les types et respectueux de la norme I18N en C++11, grâce aux modèles variadiques. Et vous pourrez les rendre très, très performants en utilisant des littéraux définis par l'utilisateur, c'est-à-dire qu'il sera possible d'écrire une incarnation entièrement statique.
J'ai une preuve de concept . À l'époque, le support de C++11 n'était pas aussi mature qu'aujourd'hui, mais vous pouvez vous faire une idée.
Adaptabilité temporelle
// foo.h
...
struct Frob {
unsigned int x;
};
...
// alpha.cpp
... printf ("%u", frob.x); ...
// bravo.cpp
... printf ("%u", frob.x); ...
// charlie.cpp
... printf ("%u", frob.x); ...
// delta.cpp
... printf ("%u", frob.x); ...
Plus tard, vos données deviennent si volumineuses que vous devez faire
// foo.h
...
unsigned long long x;
...
C'est un exercice intéressant de maintenir cela et de le faire sans bogues. Surtout quand d'autres projets, non couplés, utilisent foo.h .
Autre.
-
Bug Potentiel : Il y a beaucoup d'espace pour commettre des erreurs avec printf, surtout lorsque vous jetez des chaînes de base d'entrée utilisateur dans le mélange (pensez à votre équipe I18N). Vous devez prendre soin d'échapper correctement chacune de ces chaînes de format, vous devez être sûr de passer les bons arguments, etc. etc.
-
Les flux d'entrées/sorties rendent mon binaire plus grand. : Si c'est un problème plus important que la maintenabilité, la qualité du code, la réutilisabilité, alors (après avoir vérifié le problème !) utilisez printf.
3 votes
Pour les E/S de la console es macht nichts (cela n'a pas d'importance). Dans l'ensemble,
printf
n'est pas compatible avec les flux C++. Les flux C++ vous permettent de convertir facilement la sortie de votre console vers un fichier. (Bien que vous puissiez faire la même chose avecfprintf
).1 votes
pourquoi ne pas utiliser sprintf + cout alors ?
14 votes
Mote que vos deux lignes ne sont pas strictement équivalentes.
endl
permet également de vider le flux, comme si vous aviez écritprintf("(%d,%d)\n", x, y); fflush(stdout);
Cela peut ajouter un grand une baisse de performance si elle est exécutée de manière répétée dans une boucle. Pour obtenir un véritable équivalent de votre instruction printf en C++, vous devez écrirecout << "(" << x << "," << y << ")\n";
2 votes
@bobobo, Une faute de frappe pour "Note".
0 votes
Duplicata possible de printf et cout en C++.