C ++: “std :: endl” vs “\ n”
-
03-07-2019 - |
Question
De nombreux livres C ++ contiennent un exemple de code comme celui-ci ...
std::cout << "Test line" << std::endl;
... donc je l'ai toujours fait aussi. Mais au lieu de cela, j'ai vu beaucoup de code de développeurs qui travaillent:
std::cout << "Test line\n";
Existe-t-il une raison technique de préférer l’un l’autre, ou est-ce juste une question de style de codage?
La solution
Les différents caractères de fin de ligne importent peu, en supposant que le fichier soit ouvert en mode texte, ce que vous obtiendrez à moins que vous ne demandiez du binaire. Le programme compilé écrira ce qui convient pour le système compilé.
La seule différence est que std :: endl
vide le tampon de sortie, mais pas '\ n'
. Si vous ne voulez pas que le tampon soit vidé fréquemment, utilisez '\ n'
. Si vous le faites (par exemple, si vous souhaitez obtenir toutes les sorties et que le programme est instable), utilisez std :: endl
.
Autres conseils
La différence peut être illustrée par ce qui suit:
std::cout << std::endl;
est équivalent à
std::cout << '\n' << std::flush;
Alors,
- Utilisez
std :: endl
Si vous voulez forcer un vidage immédiat vers la sortie. - Utilisez
\ n
si vous êtes préoccupé par les performances (ce qui n'est probablement pas le cas si vous utilisez l'opérateur< <
).
J'utilise \ n
sur la plupart des lignes.
Ensuite, utilisez std :: endl
à la fin d'un paragraphe (mais ce n'est qu'une habitude et n'est généralement pas nécessaire).
Contrairement à d’autres affirmations, le caractère \ n
est associé à la séquence de fin de ligne de la plate-forme correcte uniquement si le flux est dirigé vers un fichier ( std :: cin
et std :: cout
étant spécial mais toujours des fichiers (ou des fichiers similaires)).
Il peut y avoir des problèmes de performances, std :: endl
force le vidage du flux de sortie.
Je me suis souvenu d'avoir lu à ce sujet dans la norme, alors voici:
Voir la norme C11 qui définit le comportement des flux standard, car les programmes C ++ interfacent le tube cathodique (CRT). La norme C11 doit donc régir la stratégie de vidage.
ISO / CEI 9899: 201x
7.21.3 & # 167; 7
Au démarrage du programme, trois flux de texte sont prédéfinis et n'ont pas besoin d'être ouverts explicitement & # 8212; entrée standard (pour lire entrée conventionnelle), sortie standard (pour écriture) sortie conventionnelle) et erreur standard (pour l’écriture de la sortie de diagnostic). Comme initialement ouvert, le flux d'erreur standard n'est pas entièrement mis en mémoire tampon; l'entrée standard et standard les flux de sortie sont entièrement mis en mémoire tampon si et seulement si le flux peut être déterminé de ne pas se référer vers un appareil interactif.
7.21.3 & # 167; 3
Lorsqu’un flux n’est pas mis en tampon, les caractères doivent apparaître à partir de la source ou au début. destination le plus tôt possible. Sinon, des caractères risquent d’être accumulés et transmis à ou de l'environnement hôte en tant que bloc. Quand un flux est complètement tamponné, caractères sont destinés à être transmis à ou de l'environnement hôte sous forme de bloc lorsque un tampon est rempli. Lorsqu'un flux est mis en mémoire tampon, les caractères doivent être transmis à ou de l'environnement hôte sous forme de bloc lorsqu'un caractère de nouvelle ligne est rencontré. De plus, les caractères sont destinés à être transmis en bloc à l'hôte environnement lorsqu'un tampon est rempli, lorsqu'une entrée est demandée sur un flux non tamponné, ou lorsque l’entrée est demandée sur un flux de ligne mis en mémoire tampon qui nécessite la transmission de personnages de l'environnement hôte. Le support de ces caractéristiques est défini par la mise en œuvre, et peut être affecté via les fonctions setbuf et setvbuf.
Cela signifie que std :: cout
et std :: cin
sont entièrement mis en mémoire tampon si et seulement si ils font référence à un non appareil interactif. En d'autres termes, si stdout est attaché à un terminal, il n'y a pas de différence de comportement.
Cependant, si std :: cout.sync_with_stdio (false)
est appelé, '\ n'
ne provoquera pas de vidage, même pour les périphériques interactifs. Sinon, '\ n'
équivaut à std :: endl
sauf si la canalisation vers des fichiers: référence c ++ sur std :: endl .
Un autre appel de fonction est impliqué si vous voulez utiliser std :: endl
a) std::cout << "Hello\n";
b) std::cout << "Hello" << std::endl;
a) appelle l'opérateur < <
une fois.
b) appelle deux fois l'opérateur < <
.
Ils écriront tous les deux les caractères de fin de ligne appropriés. En plus de cela, endl entraînera la validation de la mémoire tampon. En règle générale, vous ne souhaitez pas utiliser endl lorsque vous effectuez des E / S sur un fichier, car les validations inutiles peuvent avoir un impact négatif sur les performances.
Pas très grave, mais endl ne fonctionnera pas in boost :: lambda .
(cout<<_1<<endl)(3); //error
(cout<<_1<<"\n")(3); //OK , prints 3
Si vous utilisez Qt et endl, vous pourriez accidentellement utiliser le mauvais endl
, m'est arrivé aujourd'hui et j'étais comme ..WTF ??
#include <iostream>
#include <QtCore/QtCore>
#include <QtGui/QtGui>
//notice that i dont have a "using namespace std;"
int main(int argc, char** argv)
{
QApplication qapp(argc,argv);
QMainWindow mw;
mw.show();
std::cout << "Finished Execution !" << endl << "...";
// Line above printed: "Finished Execution !67006AB4..."
return qapp.exec();
}
Bien sûr, c'était mon erreur, car j'aurais dû écrire std :: endl
, mais si vous utilisez * endl
, qt et en utilisant un espace de noms std;
cela dépend de l'ordre des fichiers d'inclusion si le endl
correct sera utilisé.
Bien entendu, vous pouvez recompiler Qt pour utiliser un espace de noms. Vous obtenez donc une erreur de compilation pour l'exemple ci-dessus.
EDIT: Oublié de mentionner, le endl
de Qt est déclaré dans "qtextstream.h". qui fait partie de QtCore
* EDIT2: C ++ choisira le endl
correct si vous avez un utilisant
pour std :: cout
ou l'espace de noms std
, puisque std :: endl
se trouve dans le même espace de noms que std :: cout
, le mécanisme ADL de C ++ sélectionne std :: endl
.
J'ai toujours eu l'habitude d'utiliser std :: endl car c'est facile à voir pour moi.
Avec la référence , il s'agit d'une sortie uniquement Manipulateur E / S .
std :: endl
Insère un caractère de nouvelle ligne dans la séquence en sortie et le vide comme s'il appelait os.put (os.widen ('\ n '))
suivi de os.flush ()
.
Quand utiliser:
Ce manipulateur peut être utilisé pour produire une ligne de sortie immédiatement ,
.p. ex.
lors de l'affichage des résultats d'un processus de longue durée, de la journalisation de l'activité de plusieurs threads ou de la journalisation d'un programme susceptible de planter de manière inattendue.
Aussi
Un vidage explicite de std :: cout est également nécessaire avant un appel à std :: system, si le processus engendré effectue une opération d’écran d’écran. Dans la plupart des autres scénarios d’entrées / sorties interactives usuels, std :: endl est redondant lorsqu’il est utilisé avec std :: cout car toute entrée de std :: cin, la sortie vers std :: cerr ou la terminaison de programme force un appel vers std :: cout. .affleurer(). L'utilisation de std :: endl à la place de '\ n', encouragée par certaines sources, peut dégrader considérablement les performances de sortie.
Si vous avez l'intention d'exécuter votre programme sur autre chose que votre propre ordinateur portable, n'utilisez jamais l'instruction endl
. Surtout si vous écrivez beaucoup de lignes courtes ou comme j'ai souvent vu des caractères uniques dans un fichier. L’utilisation de endl
est connue pour tuer les systèmes de fichiers en réseau comme NFS.
Le manipulateur endl
est équivalent à '\'
. Mais endl
vide toujours le flux.
std::cout << "Test line" << std::endl; // with flush
std::cout << "Test line\n"; // no flush
Si vous n'avez pas remarqué, endl
revient à appuyer sur la touche Entrée tandis que "\ n",
revient à appuyer sur la touche Entrée, barre d'espacement.