Saya terkejut bahwa semua orang dalam pertanyaan ini mengklaim bahwa std::cout
itu jauh lebih baik daripada printf
, bahkan jika pertanyaannya hanya menanyakan perbedaan. Sekarang, ada perbedaan - std::cout
adalah C ++, dan printf
C (namun, Anda dapat menggunakannya dalam C ++, seperti hampir semua hal lain dari C). Sekarang, saya akan jujur di sini; keduanya printf
dan std::cout
memiliki kelebihan mereka.
std::cout
dapat diperpanjang. Saya tahu bahwa orang-orang akan mengatakan bahwa printf
itu juga dapat diperluas, tetapi ekstensi tersebut tidak disebutkan dalam standar C (jadi Anda harus menggunakan fitur-fitur non-standar - tetapi bahkan fitur non-standar yang umum ada), dan ekstensi tersebut adalah satu huruf (jadi mudah untuk konflik dengan format yang sudah ada).
Tidak seperti itu printf
, std::cout
sepenuhnya bergantung pada overloading operator, jadi tidak ada masalah dengan format khusus - yang Anda lakukan hanyalah mendefinisikan pengambilan subrutin std::ostream
sebagai argumen pertama dan tipe Anda sebagai yang kedua. Dengan demikian, tidak ada masalah namespace - selama Anda memiliki kelas (yang tidak terbatas pada satu karakter), Anda dapat melakukan std::ostream
overloading untuk itu.
Namun, saya ragu bahwa banyak orang ingin memperpanjang ostream
(jujur saja, saya jarang melihat ekstensi seperti itu, meskipun mudah dibuat). Namun, ada di sini jika Anda membutuhkannya.
Karena dapat dengan mudah diperhatikan, keduanya printf
dan std::cout
menggunakan sintaks yang berbeda. printf
menggunakan sintaks fungsi standar menggunakan string pola dan daftar argumen panjang variabel. Sebenarnya, printf
adalah alasan mengapa C memilikinya - printf
format terlalu kompleks untuk dapat digunakan tanpa mereka. Namun, std::cout
gunakan API yang berbeda - operator <<
API yang mengembalikan sendiri.
Secara umum, itu berarti versi C akan lebih pendek, tetapi dalam kebanyakan kasus itu tidak masalah. Perbedaannya terlihat ketika Anda mencetak banyak argumen. Jika Anda harus menulis sesuatu seperti Error 2: File not found.
, dengan asumsi nomor kesalahan, dan deskripsinya adalah placeholder, kode akan terlihat seperti ini. Kedua contoh berfungsi secara identik (well, semacam, std::endl
sebenarnya mem-flush buffer).
printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;
Meskipun ini tidak terlihat terlalu gila (hanya dua kali lebih lama), banyak hal menjadi lebih gila ketika Anda benar-benar memformat argumen, bukan hanya mencetaknya. Sebagai contoh, mencetak sesuatu seperti 0x0424
itu gila. Ini disebabkan oleh std::cout
pencampuran nilai keadaan dan aktual. Saya tidak pernah melihat bahasa di mana sesuatu seperti std::setfill
akan menjadi tipe (selain C ++, tentu saja). printf
jelas memisahkan argumen dan tipe aktual. Saya benar-benar lebih suka mempertahankan printf
versi itu (bahkan jika itu terlihat agak samar) dibandingkan dengan iostream
versi itu (karena mengandung terlalu banyak suara).
printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;
Di sinilah keunggulan nyata printf
kebohongan. The printf
format string baik ... string. Itu membuatnya sangat mudah untuk diterjemahkan, dibandingkan dengan operator <<
penyalahgunaan iostream
. Dengan asumsi bahwa gettext()
fungsi menerjemahkan, dan Anda ingin menunjukkan Error 2: File not found.
, kode untuk mendapatkan terjemahan dari string format yang ditampilkan sebelumnya akan terlihat seperti ini:
printf(gettext("Error %d: %s.\n"), id, errors[id]);
Sekarang, mari kita asumsikan bahwa kita menerjemahkan ke Fictionish, di mana nomor kesalahannya setelah deskripsi. String yang diterjemahkan akan terlihat seperti %2$s oru %1$d.\n
. Sekarang, bagaimana cara melakukannya di C ++? Yah, saya tidak tahu. Saya kira Anda dapat membuat palsu iostream
yang membangun printf
Anda dapat lulus gettext
, atau sesuatu, untuk keperluan terjemahan. Tentu saja, $
ini bukan standar C, tapi itu sangat umum sehingga aman digunakan menurut saya.
C memiliki banyak tipe integer, dan begitu juga C ++. std::cout
menangani semua jenis untuk Anda, sementara printf
memerlukan sintaksis khusus tergantung pada tipe integer (ada tipe non-integer, tetapi satu-satunya tipe non-integer yang akan Anda gunakan dalam praktiknya printf
adalah const char *
(string C, dapat diperoleh dengan menggunakan to_c
metode std::string
)). Misalnya, untuk mencetak size_t
, Anda harus menggunakan %zd
, sementara int64_t
akan membutuhkan penggunaan %"PRId64"
. Tabel tersedia di http://en.cppreference.com/w/cpp/io/c/fprintf dan http://en.cppreference.com/w/cpp/types/integer .
\0
Karena printf
menggunakan string C yang bertentangan dengan string C ++, ia tidak dapat mencetak byte NUL tanpa trik khusus. Dalam kasus-kasus tertentu itu mungkin untuk menggunakan %c
dengan '\0'
sebagai argumen, walaupun itu jelas hack.
Pembaruan: Ternyata iostream
sangat lambat sehingga biasanya lebih lambat dari hard drive Anda (jika Anda mengarahkan program Anda ke file). Menonaktifkan sinkronisasi dengan stdio
dapat membantu, jika Anda perlu menampilkan banyak data. Jika kinerja adalah masalah nyata (bukan menulis beberapa baris untuk STDOUT), gunakan saja printf
.
Semua orang berpikir bahwa mereka peduli dengan kinerja, tetapi tidak ada yang peduli untuk mengukurnya. Jawaban saya adalah bahwa I / O adalah bottleneck, tidak peduli apakah Anda menggunakan printf
atau iostream
. Saya pikir itu printf
bisa lebih cepat dari melihat cepat ke perakitan (dikompilasi dengan dentang menggunakan -O3
opsi kompilator). Dengan asumsi contoh kesalahan saya, printf
contoh melakukan panggilan jauh lebih sedikit daripada cout
contoh. Ini int main
dengan printf
:
main: @ @main
@ BB#0:
push {lr}
ldr r0, .LCPI0_0
ldr r2, .LCPI0_1
mov r1, #2
bl printf
mov r0, #0
pop {lr}
mov pc, lr
.align 2
@ BB#1:
Anda dapat dengan mudah melihat bahwa dua string, dan 2
(angka) didorong sebagai printf
argumen. Itu saja; tidak ada yang lain. Sebagai perbandingan, ini iostream
dikompilasi untuk perakitan. Tidak, tidak ada inlining; setiap operator <<
panggilan berarti panggilan lain dengan serangkaian argumen lain.
main: @ @main
@ BB#0:
push {r4, r5, lr}
ldr r4, .LCPI0_0
ldr r1, .LCPI0_1
mov r2, #6
mov r3, #0
mov r0, r4
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
mov r0, r4
mov r1, #2
bl _ZNSolsEi
ldr r1, .LCPI0_2
mov r2, #2
mov r3, #0
mov r4, r0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_3
mov r0, r4
mov r2, #14
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_4
mov r0, r4
mov r2, #1
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r0, [r4]
sub r0, r0, #24
ldr r0, [r0]
add r0, r0, r4
ldr r5, [r0, #240]
cmp r5, #0
beq .LBB0_5
@ BB#1: @ %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit
ldrb r0, [r5, #28]
cmp r0, #0
beq .LBB0_3
@ BB#2:
ldrb r0, [r5, #39]
b .LBB0_4
.LBB0_3:
mov r0, r5
bl _ZNKSt5ctypeIcE13_M_widen_initEv
ldr r0, [r5]
mov r1, #10
ldr r2, [r0, #24]
mov r0, r5
mov lr, pc
mov pc, r2
.LBB0_4: @ %_ZNKSt5ctypeIcE5widenEc.exit
lsl r0, r0, #24
asr r1, r0, #24
mov r0, r4
bl _ZNSo3putEc
bl _ZNSo5flushEv
mov r0, #0
pop {r4, r5, lr}
mov pc, lr
.LBB0_5:
bl _ZSt16__throw_bad_castv
.align 2
@ BB#6:
Namun, jujur saja, ini tidak ada artinya, karena I / O adalah hambatannya. Saya hanya ingin menunjukkan bahwa iostream
itu tidak lebih cepat karena "ketik aman". Sebagian besar implementasi C mengimplementasikan printf
format menggunakan goto yang dikomputasi, jadi printf
ini secepat mungkin, bahkan tanpa diketahui oleh kompiler printf
(bukan tidak - beberapa kompiler dapat mengoptimalkan printf
dalam kasus-kasus tertentu - string akhir konstan \n
biasanya dioptimalkan untuk puts
) .
Saya tidak tahu mengapa Anda ingin mewarisi ostream
, tetapi saya tidak peduli. Mungkin FILE
juga dengan itu.
class MyFile : public FILE {}
Benar, daftar argumen panjang variabel tidak memiliki keamanan, tetapi itu tidak masalah, karena kompiler C populer dapat mendeteksi masalah dengan printf
string format jika Anda mengaktifkan peringatan. Bahkan, Dentang bisa melakukan itu tanpa mengaktifkan peringatan.
$ cat safety.c
#include <stdio.h>
int main(void) {
printf("String: %s\n", 42);
return 0;
}
$ clang safety.c
safety.c:4:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
printf("String: %s\n", 42);
~~ ^~
%d
1 warning generated.
$ gcc -Wall safety.c
safety.c: In function ‘main’:
safety.c:4:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("String: %s\n", 42);
^
std::sort
, yang entah bagaimana sangat cepat dibandingkan denganqsort
(2 kali), di biaya ukuran yang dapat dieksekusi).Dari FAQ C ++ :
Di sisi lain,
printf
secara signifikan lebih cepat, yang dapat membenarkan menggunakannya dalam preferensi untukcout
di sangat kasus-kasus tertentu dan terbatas. Selalu profil dulu. (Lihat, misalnya, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout /)sumber
printf()
ini juga seharusnya bisa diperluas. Lihat "printf hooks" di udrepper.livejournal.com/20948.htmlprintf
tidak memiliki kemampuan seperti itu. Mekanisme pustaka non-portabel hampir tidak pada tingkat yang sama dengan diperpanjangnya iostreams sepenuhnya standar.Orang sering mengklaim itu
printf
jauh lebih cepat. Ini sebagian besar adalah mitos. Saya baru saja mengujinya, dengan hasil sebagai berikut:Kesimpulan: jika Anda hanya menginginkan baris baru, gunakan
printf
; jika tidak,cout
hampir secepat, atau bahkan lebih cepat. Rincian lebih lanjut dapat ditemukan di blog saya .Untuk lebih jelasnya, saya tidak berusaha mengatakan bahwa
iostream
selalu lebih baik daripadaprintf
; Saya hanya mencoba untuk mengatakan bahwa Anda harus membuat keputusan berdasarkan data nyata, bukan tebakan liar berdasarkan beberapa asumsi umum yang menyesatkan.Pembaruan: Ini kode lengkap yang saya gunakan untuk pengujian. Dikompilasi dengan
g++
tanpa opsi tambahan (selain dari-lrt
waktunya).sumber
printf()
danstd::ostream
adalah bahwa mantan menampilkan semua argumen dalam satu panggilan tunggal sedangkanstd::ostream
panggilan terpisah untuk masing-masing<<
. Tes hanya menghasilkan satu argumen dan baris baru, itu sebabnya Anda tidak dapat melihat perbedaannya.printf
mungkin membuat banyak panggilan di bawah penutup untuk membantu fungsi berbagai penentu format ... itu, atau itu fungsi monolitik mengerikan. Dan lagi, karena inlining, seharusnya tidak membuat perbedaan dalam kecepatan sama sekali.sprintf
ataufprintf
danstringstream
ataufstream
.Dan saya kutip :
sumber
Salah satunya adalah fungsi yang mencetak ke stdout. Yang lain adalah objek yang menyediakan beberapa fungsi anggota dan kelebihan
operator<<
cetak itu untuk stdout. Ada banyak lagi perbedaan yang bisa saya sebutkan, tetapi saya tidak yakin apa yang Anda cari.sumber
Bagi saya, perbedaan nyata yang akan membuat saya memilih 'cout' daripada 'printf' adalah:
1) << operator dapat kelebihan beban untuk kelas saya.
2) Aliran keluaran untuk cout dapat dengan mudah diubah menjadi file: (: copy paste :)
3) Saya menemukan cout lebih mudah dibaca, terutama ketika kita memiliki banyak parameter.
Satu masalah dengan
cout
adalah opsi format. Memformat data (presisi, justifikasi, dll.) Lebihprintf
mudah.sumber
printf
ke file juga dengan menggantinya denganfprintf
...Dua poin yang tidak disebutkan di sini yang saya temukan signifikan:
1)
cout
membawa banyak bagasi jika Anda belum menggunakan STL. Itu menambahkan lebih dari dua kali lebih banyak kode ke file objek Andaprintf
. Ini juga berlaku untukstring
, dan ini adalah alasan utama saya cenderung menggunakan perpustakaan string saya sendiri.2)
cout
menggunakan<<
operator yang kelebihan beban , yang menurut saya sangat disayangkan. Ini dapat menambah kebingungan jika Anda juga menggunakan<<
operator untuk tujuan yang dimaksud (bergeser ke kiri). Saya pribadi tidak suka membebani operator untuk keperluan yang tidak jelas dengan tujuan penggunaannya.Intinya: Saya akan menggunakan
cout
(danstring
) jika saya sudah menggunakan STL. Kalau tidak, saya cenderung menghindarinya.sumber
Dengan primitif, mungkin tidak masalah sepenuhnya yang mana yang Anda gunakan. Saya katakan di mana manfaatnya adalah ketika Anda ingin menampilkan objek yang kompleks.
Misalnya, jika Anda memiliki kelas,
Sekarang hal di atas mungkin tidak terlalu bagus, tetapi anggap Anda harus menampilkan ini di beberapa tempat dalam kode Anda. Tidak hanya itu, katakanlah Anda menambahkan bidang "int d." Dengan cout, Anda hanya perlu mengubahnya di satu tempat. Namun, dengan printf, Anda harus mengubahnya di banyak tempat dan tidak hanya itu, Anda harus mengingatkan diri sendiri mana yang akan ditampilkan.
Dengan itu, dengan cout, Anda dapat mengurangi banyak waktu yang dihabiskan dengan pemeliharaan kode Anda dan tidak hanya itu jika Anda menggunakan kembali objek "Sesuatu" dalam aplikasi baru, Anda tidak benar-benar perlu khawatir tentang output.
sumber
Tentu saja Anda dapat menulis "sesuatu" sedikit lebih baik untuk menjaga pemeliharaan:
Dan sedikit ujian cout vs printf, menambahkan tes 'ganda', jika ada yang ingin melakukan lebih banyak pengujian (Visual Studio 2008, rilis versi yang dapat dieksekusi):
Hasilnya adalah:
sumber
endl
jauh lebih efisien daripada'\n'
?endl
flush buffer, dan\n
tidak, meskipun saya tidak yakin ini alasan mengapa.Saya ingin menunjukkan bahwa jika Anda ingin bermain dengan utas di C ++, jika Anda menggunakan
cout
Anda bisa mendapatkan beberapa hasil yang menarik.Pertimbangkan kode ini:
Sekarang, hasilnya datang semua dikocok. Itu dapat menghasilkan hasil yang berbeda juga, coba jalankan beberapa kali:
Anda dapat menggunakannya
printf
untuk memperbaikinya, atau Anda dapat menggunakannyamutex
.Selamat bersenang-senang!
sumber
thread
s tidak membuat output menjadi gila. Saya baru saja mereproduksi dan menemukan keduanyaxyz
danABC
dalam output. Tidak ada mangling b / wABC
sebagaiABABAB
.cout
kerjanya dengan utas, tetapi saya tahu pasti bahwa kode yang Anda tampilkan bukan yang Anda gunakan untuk mendapatkan hasil tersebut. Kode Anda melewati string"ABC"
untuk utas 1 dan"xyz"
utas 2, tetapi output Anda menunjukkanAAA
danBBB
. Tolong perbaiki, karena sekarang ini membingungkan.Keduanya digunakan untuk mencetak nilai. Mereka memiliki sintaks yang sama sekali berbeda. C ++ memiliki keduanya, C hanya memiliki printf.
sumber
Saya ingin mengatakan bahwa kurangnya ekstensibilitas
printf
tidak sepenuhnya benar:Dalam C, itu benar. Tetapi di C, tidak ada kelas nyata.
Di C ++, dimungkinkan untuk membebani operator transmisi, jadi, membebani
char*
operator dan menggunakanprintf
seperti ini:bisa dimungkinkan, jika Foo membebani operator yang baik. Atau jika Anda membuat metode yang bagus. Singkatnya,
printf
sama mudahnya dengancout
saya.Argumen teknis yang dapat saya lihat untuk aliran C ++ (secara umum ... tidak hanya cout.) Adalah:
Keamanan jenis. (Dan, omong-omong, jika saya ingin mencetak satu
'\n'
saya gunakanputchar('\n')
... Saya tidak akan menggunakan bom nuklir untuk membunuh serangga.).Lebih mudah dipelajari. (tidak ada parameter "rumit" untuk dipelajari, hanya untuk digunakan
<<
dan>>
operator)Bekerja secara native dengan
std::string
(karenaprintf
adastd::string::c_str()
, tetapi untukscanf
?)Karena
printf
saya melihat:Lebih mudah, atau setidaknya lebih pendek (dalam hal karakter ditulis) pemformatan kompleks. Jauh lebih mudah dibaca, untuk saya (soal selera saya kira).
Kontrol yang lebih baik atas fungsi yang dibuat (Kembalikan jumlah karakter yang ditulis dan ada
%n
formatter: "Tidak ada yang dicetak. Argumen harus menjadi penunjuk ke int yang ditandatangani, di mana jumlah karakter yang ditulis sejauh ini disimpan." (Dari printf - Referensi C ++ )Kemungkinan debug yang lebih baik. Untuk alasan yang sama dengan argumen terakhir.
Preferensi pribadi saya pergi ke
printf
(danscanf
) fungsi, terutama karena saya suka garis pendek, dan karena saya tidak berpikir masalah mengetik pada teks sangat sulit untuk dihindari. Satu-satunya hal yang saya sesalkan dengan fungsi C-style adalah yangstd::string
tidak didukung. Kita harus melaluichar*
sebelum memberikannya kepadaprintf
(denganstd::string::c_str()
jika kita ingin membaca, tetapi bagaimana menulis?)sumber
char*
tidak akan digunakan.char*
kehidupan dan untuk berapa lama, dan bahaya yang ditentukan pengguna gips implisit.Lebih banyak perbedaan: "printf" mengembalikan nilai integer (sama dengan jumlah karakter yang dicetak) dan "cout" tidak mengembalikan apa pun
Dan.
cout << "y = " << 7;
bukan atom.printf("%s = %d", "y", 7);
adalah atom.cout melakukan pemeriksaan ketik, printf tidak.
Tidak ada yang setara dengan iostream
"% d"
sumber
cout
tidak mengembalikan apa-apa karena itu objek, bukan fungsi.operator<<
mengembalikan sesuatu (biasanya operan kirinya, tetapi nilai palsu jika ada kesalahan). Dan dalam arti apakahprintf
panggilan "atomik"?printf("%s\n",7);
%s
adalah ?printf
% s argumen harus memiliki pointer yang valid untuk null string diakhiri. Rentang memori '7' (sebuah pointer) biasanya tidak valid; kesalahan segmentasi bisa beruntung. Pada beberapa sistem, '7' mungkin mencetak banyak sampah ke konsol dan Anda harus melihatnya satu hari sebelum program berhenti. Dengan kata lain, ini adalah hal yang burukprintf
. Alat analisis statis dapat menangkap banyak masalah ini.printf
tidak melakukan pengetikan, saya tidak pernah menggunakan kompiler yang tidak memperingatkan saya tentang kesalahan ketik denganprintf
...TL; DR: Selalu lakukan riset Anda sendiri, berkenaan dengan ukuran kode mesin yang dihasilkan , kinerja , keterbacaan , dan waktu pengkodean sebelum mempercayai komentar acak daring, termasuk yang ini.
Saya bukan ahli. Saya kebetulan mendengar dua rekan kerja berbicara tentang bagaimana kita harus menghindari penggunaan C ++ di sistem embedded karena masalah kinerja. Yah, cukup menarik, saya melakukan benchmark berdasarkan tugas proyek nyata.
Dalam tugas tersebut, kami harus menulis beberapa konfigurasi ke RAM. Sesuatu seperti:
Inilah program benchmark saya (Ya, saya tahu OP bertanya tentang printf (), bukan fprintf (). Coba tangkap esensinya dan omong-omong, tautan OP menunjuk ke fprintf ()).
Program C:
Program C ++:
Saya melakukan yang terbaik untuk memoles mereka sebelum saya memutarkan keduanya 100.000 kali. Inilah hasilnya:
Program C:
Program C ++:
Ukuran file objek:
Kesimpulan: Pada platform saya yang sangat spesifik , dengan prosesor yang sangat spesifik , menjalankan versi Linux kernel yang sangat spesifik , untuk menjalankan program yang dikompilasi dengan versi GCC yang sangat spesifik , untuk menyelesaikan tugas yang sangat spesifik , saya akan mengatakan pendekatan C ++ lebih cocok karena berjalan secara signifikan lebih cepat dan memberikan keterbacaan yang jauh lebih baik. Di sisi lain, C menawarkan jejak kecil, menurut pendapat saya, hampir tidak berarti karena ukuran program tidak menjadi perhatian kami.
Ingat, YMMV.
sumber
Saya bukan seorang programmer, tetapi saya telah menjadi seorang insinyur faktor manusia. Saya merasa bahasa pemrograman harus mudah dipelajari, dipahami, dan digunakan, dan ini menuntut bahasa pemrograman yang sederhana dan konsisten. Meskipun semua bahasa adalah simbolis dan karenanya, pada intinya, sewenang-wenang, ada konvensi dan mengikuti mereka membuat bahasa lebih mudah untuk dipelajari dan digunakan.
Ada sejumlah besar fungsi dalam C ++ dan bahasa lain yang ditulis sebagai fungsi (parameter), sebuah sintaks yang awalnya digunakan untuk hubungan fungsional dalam matematika di era pra-komputer.
printf()
mengikuti sintaks ini dan jika penulis C ++ ingin membuat metode yang berbeda secara logis untuk membaca dan menulis file mereka bisa saja membuat fungsi yang berbeda menggunakan sintaksis yang sama.Dalam Python kita tentu saja dapat mencetak menggunakan
object.method
sintaks yang juga cukup standar , yaitu variablename.print, karena variabel adalah objek, tetapi dalam C ++ mereka tidak.Saya tidak menyukai sintaksis cout karena operator << tidak mengikuti aturan apa pun. Ini adalah metode atau fungsi, yaitu mengambil parameter dan melakukan sesuatu untuk itu. Namun itu ditulis seolah-olah itu adalah operator perbandingan matematis. Ini adalah pendekatan yang buruk dari sudut pandang faktor manusia.
sumber
printf
adalah fungsi sedangkancout
variabel.sumber
printf
adalah fungsi, tetapiprintf()
merupakan panggilan fungsi =)