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


569

Banyak buku C ++ berisi contoh kode seperti ini ...

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

... jadi saya selalu melakukan itu juga. Tapi saya telah melihat banyak kode dari pengembang yang bekerja seperti ini sebagai gantinya:

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

Apakah ada alasan teknis untuk memilih yang satu daripada yang lain, atau hanya karena gaya pengkodean?




25
@derobert yang satu ini lebih tua dari yang lain
Kira

3
@HediNaily memang begitu. Tetapi jawaban yang lain menurut saya sedikit lebih baik, jadi saya memilih untuk melakukannya dengan cara itu. Juga, yang lain sedikit lebih luas, juga menutupi '\n'.
derobert

stackoverflow.com/a/30968225/3163618 mungkin ada perbedaan kinerja yang signifikan.
qwr

Jawaban:


473

Karakter akhir baris yang bervariasi tidak masalah, dengan asumsi file terbuka dalam mode teks, yang adalah apa yang Anda dapatkan kecuali jika Anda meminta biner. Program yang dikompilasi akan menuliskan hal yang benar untuk sistem yang dikompilasi.

Satu-satunya perbedaan adalah std::endlflushes buffer output, dan '\n'tidak. Jika Anda tidak ingin buffer sering memerah, gunakan '\n'. Jika Anda melakukannya (misalnya, jika Anda ingin mendapatkan semua output, dan program tidak stabil), gunakan std::endl.


24
Atau pertimbangkan untuk menggunakan ::std::cerralih-alih ::std::coutkarena tidak dibuat-buat dan memerah dengan setiap operasi keluaran.
Mahakuasa

142
@Omnifarious: Tidak ada std :: cerr harus disediakan untuk kesalahan. Kedua aliran tidak disinkronkan secara bersamaan sehingga jika Anda menampilkan beberapa teks ke cout, mungkin buffered dan cerr akan langsung menuju ke output ini sehingga menghasilkan tampilan mode campuran. Gunakan cerr untuk apa yang seharusnya untuk (kesalahan) dan cout untuk apa itu dirancang untuk (interaksi normal).
Martin York

23
@Lucas: Tidak lebih dari '\ n' yang sadar platform.
CB Bailey

32
@LokiAstari: Saya tidak akan mengatakan stderrini untuk "kesalahan". Sebaliknya, itu untuk pesan diagnostik out-of-band, jika Anda mau. Seharusnya dimungkinkan untuk mengatakan ./prog > filedan menyimpan hanya muatan program yang sebenarnya, tetapi program mungkin ingin menghasilkan lebih banyak informasi status, bahkan dalam interaksi normal.
Kerrek SB

13
"Dalam banyak implementasi, output standar adalah buffer-line, dan menulis '\ n' tetap menyebabkan flush, kecuali std :: cout.sync_with_stdio (false) dieksekusi." disalin dari sini
GuLearn

249

Perbedaannya dapat diilustrasikan sebagai berikut:

std::cout << std::endl;

setara dengan

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

Begitu,

  • Gunakan std::endlJika Anda ingin memaksa flush langsung ke output.
  • Gunakan \njika Anda khawatir tentang kinerja (yang mungkin tidak terjadi jika Anda menggunakan <<operator).

Saya menggunakan \nsebagian besar baris.
Kemudian gunakan std::endldi akhir paragraf (tapi itu hanya kebiasaan dan biasanya tidak perlu).

Bertentangan dengan klaim lain, \nkarakter dipetakan ke platform yang benar hanya dari urutan baris jika aliran menuju ke suatu file ( std::cindan std::coutmenjadi file khusus tetapi tetap (atau seperti file)).


5
Dalam banyak kasus, "lihat output segera" adalah herring merah, karena coutterikat cin, artinya jika Anda membaca input dari cin, coutakan memerah terlebih dahulu. Tetapi jika Anda ingin menampilkan progress bar atau sesuatu tanpa membaca dari cin, maka yakin, pembilasan berguna.
Chris Jester-Young

9
@LokiAstari: jika Anda menggunakan << operator, Anda mungkin tidak khawatir tentang kinerja - mengapa? Saya tidak tahu itu operator<<bukan pemain, atau alternatif apa yang digunakan untuk kinerja? Tolong tunjukkan saya ke beberapa bahan untuk memahami ini lebih lanjut.
legends2k

8
@ legends2k: Ada kisah istri lama bahwa aliran C ++ tidak sebagus C printf (). Meskipun benar sampai batas tertentu perbedaan utama dalam kecepatan disebabkan oleh orang yang menggunakan aliran C ++ secara salah. stackoverflow.com/a/1042121/14065 Dalam C ++ ingatlah untuk menghapus sinkronisasi iostreams dengan C-stream sync_with_stdio(false)dan jangan menyiram output Anda terus menerus. Biarkan perpustakaan menentukan kapan harus melakukannya. stackoverflow.com/a/1926432/14065
Martin York

6
@Loki: Ada legenda urban yang sync_with_stdiomembuat iostreams secepat stdio. Tidak
Ben Voigt

2
@BenVoigt: Saya berhati-hati dengan kata-kata saya di atas (jadi saya senang dengan mereka). Ini bukan sebagai pemain seperti stdio (karena ia melakukan lebih). TETAPI banyak kesenjangan kinerja yang dikeluhkan oleh orang-orang disebabkan oleh sinkronisasi dengan stdio.
Martin York


30

Ada panggilan fungsi lain yang tersirat di sana jika Anda akan menggunakan std::endl

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

a) memanggil operator <<satu kali.
b) memanggil operator <<dua kali.


19
Mungkin jelas, tetapi memiliki dampak besar pada program berulir di mana, umumnya, versi pertama akan menulis satu baris dalam satu kesempatan di mana versi kedua dapat dibagi dengan menulis dari utas lainnya. Cukup sering saya menemukan diri saya menulis std :: cout << "hello \ n" << std :: flush untuk menghindari ini.
smparkes

Bagaimana dengan std::cout << "Hello" << "\n";?
byxor

1
@byxor Hampir sama kecuali buffer flushing seperti dijelaskan dalam jawaban lain. Bagaimanapun, itu berlebihan ketika Anda dapat menggabungkan dua string literal menjadi satu.
iBug

Nah, jika string yang akan dicetak bukan literal, maka panggilan ke <<2 dalam kasus a juga, jadi saya tidak akan mengklaim perlunya satu atau dua <<(atau dua panggilan fungsi secara umum) menjadi perbedaan antara \ndan endl.
Enrico Maria De Angelis

Lol tidak, itu bukan alasan saya menggunakan \ n.
Carlo Wood

28

Saya ingat pernah membaca tentang ini dalam standar, jadi begini:

Lihat standar C11 yang mendefinisikan bagaimana stream standar berperilaku, ketika program C ++ antarmuka CRT, standar C11 harus mengatur kebijakan pembilasan di sini.

ISO / IEC 9899: 201x

7.21.3 §7

Pada startup program, tiga stream teks sudah ditentukan sebelumnya dan tidak perlu dibuka secara eksplisit - input standar (untuk membaca input konvensional), output standar (untuk menulis output konvensional), dan standard error (untuk menulis output diagnostik). Seperti yang awalnya dibuka, aliran kesalahan standar tidak sepenuhnya buffered; input standar dan output stream standar sepenuhnya buffered jika dan hanya jika aliran dapat ditentukan untuk tidak merujuk ke perangkat interaktif.

7.21.3 §3

Ketika aliran tidak ditemukan, karakter dimaksudkan untuk muncul dari sumber atau di tujuan sesegera mungkin. Kalau tidak, karakter dapat diakumulasikan dan dikirim ke atau dari lingkungan host sebagai blok. Ketika aliran sepenuhnya buffered, karakter dimaksudkan untuk dikirim ke atau dari lingkungan host sebagai blok ketika buffer diisi. Ketika aliran buffer line, karakter dimaksudkan untuk dikirim ke atau dari lingkungan host sebagai blok ketika karakter baris baru ditemui. Selain itu, karakter dimaksudkan untuk ditransmisikan sebagai blok ke lingkungan host ketika buffer diisi, ketika input diminta pada stream yang tidak dikonstruksikan, atau ketika input diminta pada jalur buffered stream yang membutuhkan transmisi karakter dari lingkungan host .

Ini berarti bahwa std::coutdan std::cinsepenuhnya buffered jika dan hanya jika mereka merujuk ke perangkat non-interaktif. Dengan kata lain, jika stdout dilampirkan ke terminal maka tidak ada perbedaan perilaku.

Namun, jika std::cout.sync_with_stdio(false)dipanggil, maka '\n'tidak akan menyebabkan flush bahkan ke perangkat interaktif. Sebaliknya '\n'setara dengan std::endlkecuali pemipaan ke file: c ++ ref on std :: endl .


19

Mereka berdua akan menulis karakter end-of-line yang sesuai. Selain itu endl akan menyebabkan buffer berkomitmen. Anda biasanya tidak ingin menggunakan endl ketika melakukan file I / O karena komitmen yang tidak perlu dapat memengaruhi kinerja.



10

Jika Anda menggunakan Qt dan endl, Anda dapat secara tidak sengaja menggunakan yang salah endlyang memberi Anda hasil yang sangat mengejutkan. Lihat cuplikan kode berikut:

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

Perhatikan bahwa saya menulis endlalih-alih std::endl(yang seharusnya sudah benar) dan ternyata ada endlfungsi yang didefinisikan dalam qtextstream.h (yang merupakan bagian dari QtCore).

Menggunakan "\n"alih-alih endlsepenuhnya menghindari potensi masalah namespace. Ini juga merupakan contoh yang baik mengapa menempatkan simbol ke namespace global (seperti Qt tidak secara default) adalah ide yang buruk.


31
Urgh! Siapa yang mau jadi using namespace std;?? :-)
Steve Folly

2
Menjijikan. Terima kasih atas komentarnya, saya yakin orang lain akan mengalami itu.
Kepala Geek

@SteveFolly saya lakukan. Kenapa tidak?
ʇolɐǝz ǝɥʇ qoq

@ ʇolɐǝzǝɥʇqoq Tidak apa-apa asalkan Anda tidak melakukannya di file header.
smerlin

1
@ ʇolɐǝzǝɥʇqoq Harap hindari using namespace std;. Ini dianggap praktik buruk. Lihat Mengapa “menggunakan namespace std;” dianggap praktik yang buruk?
LF

2

Saya selalu punya kebiasaan hanya menggunakan std :: endl karena mudah bagi saya untuk melihatnya.


2

The std::endlmanipulator setara dengan '\n'. Tapi std::endlselalu menyiram arus.

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

1

Jika Anda berniat untuk menjalankan program Anda selain laptop Anda sendiri, jangan pernah menggunakan endlpernyataan itu. Terutama jika Anda menulis banyak baris pendek atau seperti yang sering saya lihat karakter tunggal ke file. Penggunaan endlini tahu untuk membunuh sistem file jaringan seperti NFS.


Apakah itu karena pembilasan? Saya bisa melihat bagaimana itu mungkin.
Kepala Geek

@Head Memang. Saya juga melihatnya merusak kinerja IO disk.
sbi

0

Dengan referensi Ini adalah manipulator I / O keluaran saja .

std::endlMenyisipkan karakter baris baru ke dalam urutan output os dan flush seolah-olah dengan memanggil os.put(os.widen('\n'))diikuti oleh os.flush().

Kapan harus menggunakan:

Manipulator ini dapat digunakan untuk menghasilkan garis output segera ,

misalnya

saat menampilkan output dari proses yang berjalan lama, aktivitas pencatatan banyak utas atau aktivitas pencatatan program yang mungkin macet secara tak terduga.

Juga

Flush eksplisit std :: cout juga diperlukan sebelum panggilan ke std :: system, jika proses spawned melakukan semua layar I / O. Dalam sebagian besar skenario I / O interaktif biasa lainnya, std :: endl berlebihan jika digunakan dengan std :: cout karena setiap input dari std :: cin, output ke std :: cerr, atau penghentian program memaksa panggilan ke std :: cout .menyiram(). Penggunaan std :: endl sebagai pengganti '\ n', didorong oleh beberapa sumber, dapat secara signifikan menurunkan kinerja keluaran.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.