C ++: "std :: endl" vs "\ n"


569

De nombreux livres C ++ contiennent des exemples de code comme celui-ci ...

std::cout << "Test line" << std::endl;

... donc je l'ai toujours fait aussi. Mais j'ai vu à la place beaucoup de code de développeurs qui travaillent comme ceci:

std::cout << "Test line\n";

Y a-t-il une raison technique de préférer l'un à l'autre, ou s'agit-il simplement d'une question de style de codage?




25
@derobert celui-ci est plus ancien que l'autre
Kira

3
@HediNaily c'est bien le cas. Mais la réponse de l'autre me semble légèrement meilleure, alors j'ai choisi de le faire de cette façon. De plus, l'autre est légèrement plus large, couvrant également '\n'.
derobert

stackoverflow.com/a/30968225/3163618 il peut y avoir une différence de performances significative.
qwr

Réponses:


473

Les différents caractères de fin de ligne n'ont pas d'importance, en supposant que le fichier est ouvert en mode texte, ce que vous obtenez à moins que vous ne demandiez le binaire. Le programme compilé écrira la bonne chose pour le système compilé.

La seule différence est qu'il std::endlvide le tampon de sortie, et '\n'ne le fait pas. Si vous ne voulez pas que le tampon soit vidé fréquemment, utilisez '\n'. Si vous le faites (par exemple, si vous voulez obtenir toute la sortie et que le programme est instable), utilisez std::endl.


24
Ou envisagez d'utiliser ::std::cerrau lieu de ::std::coutcar il est sans tampon et vidé avec chaque opération de sortie.
Omnifarious

142
@Omnifarious: Aucun std :: cerr ne doit être réservé aux erreurs. Les deux flux ne sont pas synchronisés ensemble, donc si vous envoyez du texte au cout, il peut être mis en mémoire tampon et le cerr ira directement à la sortie, ce qui donnera un affichage en mode mixte. Utilisez cerr pour ce qu'il est censé être (erreurs) et cout pour ce pour quoi il est conçu (interaction normale).
Martin York

23
@Lucas: Pas plus que '\ n' n'est conscient de la plateforme.
CB Bailey

32
@LokiAstari: Je ne dirais pas que stderrc'est pour les "erreurs". C'est plutôt pour les messages de diagnostic hors bande, si vous voulez. Il devrait être possible de dire ./prog > fileet de stocker uniquement la véritable charge utile du programme, mais le programme peut souhaiter afficher beaucoup plus d'informations sur l'état, même en interaction normale.
Kerrek SB

13
"Dans de nombreuses implémentations, la sortie standard est mise en mémoire tampon de ligne et l'écriture '\ n' provoque quand même un vidage, à moins que std :: cout.sync_with_stdio (false) n'ait été exécuté." copié d'ici
GuLearn

249

La différence peut être illustrée par ce qui suit:

std::cout << std::endl;

est équivalent à

std::cout << '\n' << std::flush;

Donc,

  • Utilisez std::endlSi vous souhaitez forcer un vidage immédiat sur la sortie.
  • À utiliser \nsi vous vous inquiétez des performances (ce qui n'est probablement pas le cas si vous utilisez l' <<opérateur).

J'utilise \nsur la plupart des lignes.
Utilisez ensuite std::endlà la fin d'un paragraphe (mais c'est juste une habitude et généralement pas nécessaire).

Contrairement à d'autres affirmations, le \ncaractère n'est mappé sur la séquence de fin de ligne de plate-forme correcte que si le flux va vers un fichier ( std::cinet qu'il std::coutest spécial mais toujours des fichiers (ou de type fichier)).


5
Dans de nombreux cas, le "voir la sortie immédiatement" est un hareng rouge, car il coutest lié à cin, ce qui signifie que si vous lisez une entrée cin, coutil sera vidé en premier. Mais si vous souhaitez afficher une barre de progression ou quelque chose sans lire cin, alors, le rinçage est utile.
Chris Jester-Young

9
@LokiAstari: si vous utilisez l'opérateur <<, vous n'êtes probablement pas préoccupé par les performances - pourquoi? Je ne savais pas que ce operator<<n'était pas performant, ou quelle alternative utiliser pour la performance? Veuillez m'indiquer du matériel pour mieux comprendre cela.
legends2k

8
@ legends2k: Il existe une vieille histoire de femmes selon laquelle les flux C ++ ne sont pas aussi performants que C printf (). Bien que cela soit vrai dans une certaine mesure, la principale différence de vitesse est causée par l'utilisation incorrecte des flux C ++. stackoverflow.com/a/1042121/14065 En C ++, n'oubliez pas de désynchroniser les flux ios avec les flux C sync_with_stdio(false)et de ne pas vider votre sortie en continu. Laissez la bibliothèque déterminer quand le faire. stackoverflow.com/a/1926432/14065
Martin York

6
@Loki: Il y a une légende urbaine qui sync_with_stdiorend les iostreams aussi rapides que stdio. Ce n'est pas le cas
Ben Voigt du

2
@BenVoigt: J'ai fait attention à ma formulation ci-dessus (donc je suis content avec eux). Il n'est pas aussi performant que stdio (car il en fait plus). MAIS une grande partie de l'écart de performance dont se plaignent les gens est due à la synchronisation avec stdio.
Martin York


30

Il y a un autre appel de fonction implicite là-dedans si vous allez utiliser std::endl

a) std::cout << "Hello\n";
b) std::cout << "Hello" << std::endl;

a) appelle <<une fois l' opérateur .
b) appelle <<deux fois l' opérateur .


19
Cela peut être évident, mais cela a un impact énorme sur les programmes threadés où, généralement, la première version écrit une seule ligne en une seule fois où la deuxième version peut être divisée par des écritures à partir d'autres threads. Souvent, je me retrouve à écrire std :: cout << "hello \ n" << std :: flush pour éviter cela.
smparkes

Et alors std::cout << "Hello" << "\n";?
byxor

1
@byxor Presque la même chose, sauf le vidage du tampon, comme décrit dans d'autres réponses. Quoi qu'il en soit, c'est redondant lorsque vous pouvez fusionner les deux littéraux de chaîne en un seul.
iBug

Eh bien, si la chaîne à imprimer n'est pas un littéral, les appels à la <<seraient également 2 dans le cas a , donc je ne dirais pas que le besoin d'un ou deux <<(ou deux appels de fonction en général) soit un différence entre \net endl.
Enrico Maria De Angelis

Lol non, ce n'est pas la raison pour laquelle j'utilise \ n.
Carlo Wood

28

Je me souviens avoir lu à ce sujet dans la norme, alors voici:

Voir la norme C11 qui définit comment les flux standard se comportent, car les programmes C ++ interfacent avec le CRT, la norme C11 devrait régir la politique de vidage ici.

ISO / CEI 9899: 201x

7.21.3 §7

Au démarrage du programme, trois flux de texte sont prédéfinis et n'ont pas besoin d'être ouverts explicitement - entrée standard (pour lire l'entrée conventionnelle), sortie standard (pour écrire la sortie conventionnelle) et erreur standard (pour écrire la sortie de diagnostic). Comme initialement ouvert, le flux d'erreur standard n'est pas entièrement mis en mémoire tampon; les flux d'entrée et de sortie standard sont entièrement tamponnés si et seulement si le flux peut être déterminé comme ne faisant pas référence à un appareil interactif.

7.21.3 §3

Lorsqu'un flux n'est pas mis en mémoire tampon, les caractères sont censés apparaître dès la source ou à destination dès que possible. Sinon, les caractères peuvent être accumulés et transmis vers ou depuis l'environnement hôte sous forme de bloc. Lorsqu'un flux est entièrement tamponné, les caractères sont destinés à être transmis vers ou depuis l'environnement hôte sous forme de bloc lorsqu'un tampon est rempli. Lorsqu'un flux est mis en mémoire tampon de ligne, les caractères sont destinés à être transmis vers ou depuis l'environnement hôte en tant que bloc lorsqu'un caractère de nouvelle ligne est rencontré. De plus, les caractères sont destinés à être transmis sous forme de bloc à l'environnement hôte lorsqu'un tampon est rempli, lorsqu'une entrée est demandée sur un flux non tamponné, ou lorsqu'une entrée est demandée sur un flux tamponné de ligne qui nécessite la transmission de caractères de l'environnement hôte .

Cela signifie que std::coutet std::cinsont entièrement tamponnés si et seulement si font référence à un appareil non 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'cela ne provoquera pas de vidage, même sur les appareils interactifs. Sinon, '\n'c'est équivalent à std::endlmoins de canaliser vers des fichiers: ref c ++ sur std :: endl .


19

Ils écriront tous les deux le ou les caractères de fin de ligne appropriés. En plus de cette fin, le tampon sera validé. Vous ne souhaitez généralement pas utiliser endl lors des E / S sur les fichiers car les validations inutiles peuvent avoir un impact sur les performances.



10

Si vous utilisez Qt et endl, vous pourriez accidentellement finir par utiliser une erreur endlqui vous donnera des résultats très surprenants. Voir l'extrait de code suivant:

#include <iostream>
#include <QtCore/QtCore> 
#include <QtGui/QtGui>

// notice that there is no "using namespace std;"
int main(int argc, char** argv)
{
    QApplication qapp(argc,argv);
    QMainWindow mw;
    mw.show();
    std::cout << "Finished Execution!" << endl;
    // This prints something similar to: "Finished Execution!67006AB4"
    return qapp.exec();
}

Notez que j'ai écrit à la endlplace de std::endl(ce qui aurait été correct) et apparemment il y a une endlfonction définie dans qtextstream.h (qui fait partie de QtCore).

L'utilisation "\n"au lieu de endlcontourner complètement tous les problèmes d'espace de noms potentiels. C'est aussi un bon exemple pour lequel placer des symboles dans l'espace de noms global (comme Qt le fait par défaut) est une mauvaise idée.


31
Urgh! Qui voudrait jamais être using namespace std;?? :-)
Steve Folly

2
Méchant. Merci pour le commentaire, je suis sûr que d'autres s'y retrouveront.
Head Geek

@SteveFolly je fais. Pourquoi pas?
ʇolɐǝz ǝɥʇ qoq

@ ʇolɐǝzǝɥʇqoq C'est correct tant que vous ne le faites pas dans les fichiers d'en-tête.
smerlin

1
@ ʇolɐǝzǝɥʇqoq Veuillez éviter using namespace std;. C'est considéré comme une mauvaise pratique. Voir Pourquoi utilise «namespace std;» considéré comme une mauvaise pratique?
LF

2

J'ai toujours eu l'habitude d'utiliser simplement std :: endl parce que c'est facile à voir pour moi.


2

Le std::endlmanipulateur est équivalent à '\n'. Mais std::endlvide toujours le flux.

std::cout << "Test line" << std::endl; // with flush
std::cout << "Test line\n"; // no flush

1

Si vous avez l'intention d'exécuter votre programme sur autre chose que votre propre ordinateur portable, n'utilisez jamais l' endlinstruction. Surtout si vous écrivez beaucoup de lignes courtes ou comme j'ai souvent vu des caractères uniques dans un fichier. L'utilisation de endlis know pour tuer les systèmes de fichiers en réseau comme NFS.


Est-ce dû au rinçage? Je peux voir comment cela pourrait être possible.
Head Geek

@Head Indeed. Je l'ai également vu détruire les performances d'E / S du disque.
sbi

0

Avec référence Il s'agit d'un manipulateur d'E / S uniquement en sortie .

std::endlInsère un caractère de nouvelle ligne dans le SE de la séquence de sortie et le vide comme si en appelant os.put(os.widen('\n'))suivi de os.flush().

Quand utiliser:

Ce manipulateur peut être utilisé pour produire une ligne de sortie immédiatement ,

par exemple

lors de l'affichage de la sortie d'un processus de longue durée, l'activité de journalisation de plusieurs threads ou l'activité de journalisation d'un programme qui peut se bloquer de façon inattendue.

Aussi

Un vidage explicite de std :: cout est également nécessaire avant un appel à std :: system, si le processus généré effectue des E / S d'écran. Dans la plupart des autres scénarios d'E / S interactifs habituels, std :: endl est redondant lorsqu'il est utilisé avec std :: cout car toute entrée provenant de std :: cin, sortie vers std :: cerr ou la fin d'un programme force un appel à 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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.