web-dev-qa-db-fra.com

"\ n" ou '\ n' ou std :: endl à std :: cout?

Cela faisait de nombreuses années maintenant que je cessais d'utiliser std::endl Pour terminer les lignes lorsque j'écrivais dans std::cout Et commençais à utiliser "\n" À la place.

Mais maintenant, je commence à voir plus d'extraits de code en utilisant '\n' À la place, et j'ai commencé à me demander ce qui pourrait être mieux.

En plus de l'évidence que l'un est une chaîne et l'autre un caractère, y a-t-il un avantage à utiliser ceci:

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

Sur ceci:

std::cout << variable << "\n";

Ajout tardif:

Quand j'ai posé cette question, j'ai semblé penser que newline '\n' Avait vidé le tampon. Maintenant je sais que cela dépend.

Par défaut, std::cin Est lié à l'ancien flux C stdinFILE* Et std::cout Est lié à stdout. Le flushing sur newline provient de cette liaison. Par défaut, stdout, s'il est connecté à un terminal, est mis en ligne. Cela signifie qu'une nouvelle ligne videra ses tampons. Ainsi, lors de l’impression d’une nouvelle ligne utilisant std::cout, Cela entraînera le vidage de stdout.

Si stdout n’est pas connecté à un terminal (par exemple, la sortie a été redirigée ou est redirigée), ou si le lien entre std::cout Et stdout est rompu, les nouvelles lignes seront alors coupées. ne pas vider quoi que ce soit.

91

Réellement, '\n' devrait être la valeur par défaut. À moins que vous ne vouliez également vider explicitement le flux (et quand et pourquoi voudriez-vous le faire?), Il n'est pas nécessaire d'utiliser std::endl du tout.1
Bien sûr, de nombreux livres et tutoriels utilisent std::endl par défaut. Cela est regrettable et pourrait conduire à bugs de performances graves .

Je suppose qu'il y a peu de différence entre utiliser '\n' ou en utilisant "\n", mais ce dernier est un tableau de (deux) caractères, qui doit être imprimé caractère par caractère, pour lequel une boucle doit être créée, ce qui est plus complexe que la sortie d’un seul caractère. Bien sûr, lorsque vous faites IO, cela compte rarement, mais en cas de doute, lorsque vous souhaitez générer un littéral de caractère, générez un littéral de caractère plutôt que toute une chaîne de caractères.
Un effet secondaire intéressant de cette opération est que vous indiquez dans votre code que vous vouliez ne générer qu'un seul caractère, et non juste accidentellement fait cela.


1Notez que std::cout est lié à std::cin _ par défaut, ce qui conduit à std::cout en cours de vidage avant toute opération de saisie, de sorte que toute invite soit imprimée avant que l'utilisateur n'ait à saisir quelque chose.

101
sbi

Il n'y a pas le meilleur. Vous utilisez ce dont vous avez besoin:

  • '\ n' - pour terminer la ligne
  • "une chaîne\n" - la fin de la ligne après une chaîne
  • std::endl - pour terminer la ligne et vider le flux
14
BЈовић

Ils font des choses différentes. "\n" Affiche une nouvelle ligne (dans la représentation spécifique à la plate-forme appropriée, de sorte qu'elle génère un "\r\n" sous Windows), mais std::endl fait la même chose et vide le flux. Généralement, vous n'avez pas besoin de vider le flux immédiatement et cela ne vous coûtera que des performances. Par conséquent, pour la plupart, il n'y a aucune raison d'utiliser std::endl.

14
jalf
  • std::cout << variable << std::endl;

    std::endl Affiche une nouvelle ligne, mais vide également le flux de sortie. En d'autres termes, même effet que

    std::cout << variable << '\n'; // output newline
    std::cout.flush();      // then flush 
    
  • std::cout << variable << '\n';

    '\n' Affiche une nouvelle ligne pour un char,. Par conséquent, ostream& operator<< (ostream& os, char c); sera utilisé.

  • std::cout << variable << "\n";

    "\n" Est un const char[2], Donc ostream& operator<< (ostream& os, const char* s); sera utilisé. Nous pouvons imaginer que cette fonction contiendra une boucle, nous pourrions même dire qu'il est excessif d'imprimer une nouvelle ligne.

4
zangw

Edit: j’ai mal formulé ma réponse, ce qui a peut-être amené les gens à croire que je pensais que "\ n" imprimait un caractère nul. C'est bien sûr faux :)

Edit 2: Après avoir regardé une référence C++, chars sont passés par référence de toute façon, donc il n'y a pas de différence. La seule différence est qu'il faudra rechercher dans la chaîne de caractères un caractère de délimitation. Ce qui suit n'est pas correct à cause de ce fait.

'\n' Serait légèrement plus efficace que "\n", Car ce dernier contient également un caractère nul à la fin, ce qui signifie que vous envoyez un char* À operator<<() (généralement 4 octets sur un système 32 bits) par opposition à un seul octet pour un char.

En pratique, cela n’est pas pertinent. Personnellement, je suis la convention que Vladimir a décrite. *

4
Chris Parton

std::endl chasse le flux. Lorsque cela vous intéresse, par exemple parce que vous vous attendez à ce que votre sortie soit visible par l'utilisateur rapidement - vous devez utiliser std::endl au lieu d'écrire '\n' au flux (sous forme de caractère isolé ou de partie de chaîne).

Parfois, vous pouvez vous en sortir sans purger explicitement le flux vous-même; par exemple. dans un environnement linux, si cout est synchronisé avec STDOUT (valeur par défaut) et écrit sur un terminal, le flux sera par défaut ligne mise en mémoire tampon = et effacera automatiquement chaque fois que vous écrivez une nouvelle ligne.

Cependant, il est risqué de s'appuyer sur ce comportement. par exemple. dans le même environnement linux, si vous décidez d'exécuter votre programme avec stdout redirigé vers un fichier ou redirigé vers un autre processus, le flux sera par défaut block buffered.

De même, si vous décidez par la suite de désactiver la synchronisation avec stdio (pour des raisons d'efficacité, par exemple), les implémentations auront tendance à utiliser les mécanismes de mise en mémoire tampon de iostream, qui ne disposent pas du mode de mise en mémoire tampon des lignes.

J'ai vu beaucoup de productivité gaspillée à cause de cette erreur; si la sortie doit être visible quand elle est écrite, vous devriez soit utiliser std::endl explicitement (ou utilisez std::flush ou std::ostream::flush, mais je trouve généralement std::endl plus pratique), ou faites autre chose pour que le vidage se produise assez souvent, par exemple en configurant stdout pour qu'il soit mis en mémoire tampon (en supposant que cela soit adéquat).

3
Hurkyl