Jawaban:
Saya terkejut bahwa semua orang dalam pertanyaan ini mengklaim bahwa std::coutitu jauh lebih baik daripada printf, bahkan jika pertanyaannya hanya menanyakan perbedaan. Sekarang, ada perbedaan - std::coutadalah C ++, dan printfC (namun, Anda dapat menggunakannya dalam C ++, seperti hampir semua hal lain dari C). Sekarang, saya akan jujur di sini; keduanya printfdan std::coutmemiliki kelebihan mereka.
std::coutdapat diperpanjang. Saya tahu bahwa orang-orang akan mengatakan bahwa printfitu 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::coutsepenuhnya bergantung pada overloading operator, jadi tidak ada masalah dengan format khusus - yang Anda lakukan hanyalah mendefinisikan pengambilan subrutin std::ostreamsebagai 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::ostreamoverloading 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 printfdan std::coutmenggunakan sintaks yang berbeda. printfmenggunakan sintaks fungsi standar menggunakan string pola dan daftar argumen panjang variabel. Sebenarnya, printfadalah alasan mengapa C memilikinya - printfformat terlalu kompleks untuk dapat digunakan tanpa mereka. Namun, std::coutgunakan 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::endlsebenarnya 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 0x0424itu gila. Ini disebabkan oleh std::coutpencampuran nilai keadaan dan aktual. Saya tidak pernah melihat bahasa di mana sesuatu seperti std::setfillakan menjadi tipe (selain C ++, tentu saja). printfjelas memisahkan argumen dan tipe aktual. Saya benar-benar lebih suka mempertahankan printfversi itu (bahkan jika itu terlihat agak samar) dibandingkan dengan iostreamversi 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 printfkebohongan. The printfformat 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 iostreamyang membangun printfAnda 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::coutmenangani semua jenis untuk Anda, sementara printfmemerlukan sintaksis khusus tergantung pada tipe integer (ada tipe non-integer, tetapi satu-satunya tipe non-integer yang akan Anda gunakan dalam praktiknya printfadalah const char *(string C, dapat diperoleh dengan menggunakan to_cmetode std::string)). Misalnya, untuk mencetak size_t, Anda harus menggunakan %zd, sementara int64_takan membutuhkan penggunaan %"PRId64". Tabel tersedia di http://en.cppreference.com/w/cpp/io/c/fprintf dan http://en.cppreference.com/w/cpp/types/integer .
\0Karena printfmenggunakan string C yang bertentangan dengan string C ++, ia tidak dapat mencetak byte NUL tanpa trik khusus. Dalam kasus-kasus tertentu itu mungkin untuk menggunakan %cdengan '\0'sebagai argumen, walaupun itu jelas hack.
Pembaruan: Ternyata iostreamsangat lambat sehingga biasanya lebih lambat dari hard drive Anda (jika Anda mengarahkan program Anda ke file). Menonaktifkan sinkronisasi dengan stdiodapat 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 printfatau iostream. Saya pikir itu printf bisa lebih cepat dari melihat cepat ke perakitan (dikompilasi dengan dentang menggunakan -O3opsi kompilator). Dengan asumsi contoh kesalahan saya, printfcontoh melakukan panggilan jauh lebih sedikit daripada coutcontoh. Ini int maindengan 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 printfargumen. Itu saja; tidak ada yang lain. Sebagai perbandingan, ini iostreamdikompilasi 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 iostreamitu tidak lebih cepat karena "ketik aman". Sebagian besar implementasi C mengimplementasikan printfformat menggunakan goto yang dikomputasi, jadi printfini secepat mungkin, bahkan tanpa diketahui oleh kompiler printf(bukan tidak - beberapa kompiler dapat mengoptimalkan printfdalam kasus-kasus tertentu - string akhir konstan \nbiasanya dioptimalkan untuk puts) .
Saya tidak tahu mengapa Anda ingin mewarisi ostream, tetapi saya tidak peduli. Mungkin FILEjuga 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 printfstring 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 dengan qsort(2 kali), di biaya ukuran yang dapat dieksekusi).
Dari FAQ C ++ :
[15.1] Mengapa saya harus menggunakan
<iostream>daripada tradisional<cstdio>?Tingkatkan keamanan jenis, kurangi kesalahan, memungkinkan ekstensibilitas, dan memberikan warisan.
printf()mungkin tidak rusak, danscanf()mungkin layak huni meskipun rentan kesalahan, namun keduanya terbatas sehubungan dengan apa yang dapat dilakukan C ++ I / O. C ++ I / O (menggunakan<<dan>>) adalah, relatif terhadap C (menggunakanprintf()danscanf()):
- Lebih banyak tipe-aman: Dengan
<iostream>, jenis objek yang saya / O akan dikenal secara statis oleh kompiler. Sebaliknya,<cstdio>gunakan bidang "%" untuk mengetahui jenis secara dinamis.- Kurang rawan kesalahan: Dengan
<iostream>, tidak ada token "%" yang berlebihan yang harus konsisten dengan objek aktual yang saya / O miliki. Menghapus redundansi menghapus kelas kesalahan.- Extensible:
<iostream>Mekanisme C ++ memungkinkan tipe baru yang ditentukan pengguna menjadi I / O'd tanpa melanggar kode yang ada. Bayangkan kekacauan jika semua orang secara bersamaan menambahkan bidang "%" yang tidak kompatibel keprintf()danscanf()?!- Inheritable:
<iostream>Mekanisme C ++ dibangun dari kelas nyata sepertistd::ostreamdanstd::istream. Tidak seperti<cstdio>ituFILE*, ini adalah kelas nyata dan karenanya dapat diwariskan. Ini berarti Anda dapat memiliki hal-hal lain yang ditetapkan pengguna yang terlihat dan bertindak seperti aliran, namun itu melakukan hal-hal aneh dan indah apa pun yang Anda inginkan. Anda secara otomatis dapat menggunakan zillions baris kode I / O yang ditulis oleh pengguna yang bahkan tidak Anda kenal, dan mereka tidak perlu tahu tentang kelas "aliran diperluas" Anda.
Di sisi lain, printfsecara signifikan lebih cepat, yang dapat membenarkan menggunakannya dalam preferensi untuk coutdi 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 /)
printf()ini juga seharusnya bisa diperluas. Lihat "printf hooks" di udrepper.livejournal.com/20948.html
printftidak memiliki kemampuan seperti itu. Mekanisme pustaka non-portabel hampir tidak pada tingkat yang sama dengan diperpanjangnya iostreams sepenuhnya standar.
Orang sering mengklaim itu printfjauh lebih cepat. Ini sebagian besar adalah mitos. Saya baru saja mengujinya, dengan hasil sebagai berikut:
cout with only endl 1461.310252 ms
cout with only '\n' 343.080217 ms
printf with only '\n' 90.295948 ms
cout with string constant and endl 1892.975381 ms
cout with string constant and '\n' 416.123446 ms
printf with string constant and '\n' 472.073070 ms
cout with some stuff and endl 3496.489748 ms
cout with some stuff and '\n' 2638.272046 ms
printf with some stuff and '\n' 2520.318314 ms
Kesimpulan: jika Anda hanya menginginkan baris baru, gunakan printf; jika tidak, couthampir secepat, atau bahkan lebih cepat. Rincian lebih lanjut dapat ditemukan di blog saya .
Untuk lebih jelasnya, saya tidak berusaha mengatakan bahwa iostreamselalu lebih baik daripada printf; 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 -lrtwaktunya).
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
timespec d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
clock_gettime(CLOCK_REALTIME, &d_start);
}
~TimedSection() {
timespec end;
clock_gettime(CLOCK_REALTIME, &end);
double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
std::cerr << d_name << '\t' << std::fixed << duration << " ms\n";
}
};
int main() {
const int iters = 10000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
}
printf()dan std::ostreamadalah bahwa mantan menampilkan semua argumen dalam satu panggilan tunggal sedangkan std::ostreampanggilan terpisah untuk masing-masing <<. Tes hanya menghasilkan satu argumen dan baris baru, itu sebabnya Anda tidak dapat melihat perbedaannya.
printfmungkin 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.
sprintfatau fprintfdan stringstreamatau fstream.
Dan saya kutip :
Dalam istilah tingkat tinggi, perbedaan utama adalah keselamatan jenis (cstdio tidak memilikinya), kinerja (sebagian besar implementasi iostreams lebih lambat daripada yang cstdio) dan ekstensibilitas (iostreams memungkinkan target output khusus dan output mulus dari tipe yang ditentukan pengguna).
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.
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 :)
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
streambuf* sbuf = cout.rdbuf();
cout.rdbuf(file.rdbuf());
cout << "This is sent to file" << endl;
cout.rdbuf(sbuf);
cout << "This is also sent to prompt" << endl;
return 0;
}
3) Saya menemukan cout lebih mudah dibaca, terutama ketika kita memiliki banyak parameter.
Satu masalah dengan coutadalah opsi format. Memformat data (presisi, justifikasi, dll.) Lebih printfmudah.
printfke file juga dengan menggantinya dengan fprintf...
Dua poin yang tidak disebutkan di sini yang saya temukan signifikan:
1) coutmembawa banyak bagasi jika Anda belum menggunakan STL. Itu menambahkan lebih dari dua kali lebih banyak kode ke file objek Anda printf. Ini juga berlaku untuk string, dan ini adalah alasan utama saya cenderung menggunakan perpustakaan string saya sendiri.
2) coutmenggunakan <<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(dan string) jika saya sudah menggunakan STL. Kalau tidak, saya cenderung menghindarinya.
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,
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// output with printf
printf("%i, %i, %i\n", s.a, s.b, s.c);
// output with cout
cout << s << endl;
return 0;
}
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.
Tentu saja Anda dapat menulis "sesuatu" sedikit lebih baik untuk menjaga pemeliharaan:
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
void print() const { printf("%i, %i, %i\n", a, b, c); }
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// Output with printf
s.print(); // Simple as well, isn't it?
// Output with cout
cout << s << endl;
return 0;
}
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):
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
//timespec d_start;
clock_t d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
//clock_gettime(CLOCK_REALTIME, &d_start);
d_start = clock();
}
~TimedSection() {
clock_t end;
//clock_gettime(CLOCK_REALTIME, &end);
end = clock();
double duration = /*1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
*/
(double) (end - d_start) / CLOCKS_PER_SEC;
std::cerr << d_name << '\t' << std::fixed << duration * 1000.0 << " ms\n";
}
};
int main() {
const int iters = 1000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
{
TimedSection s("cout with formatted double (width & precision once)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
std::cout.width(8);
for (int i = 0; i < iters; ++i)
std::cout << text << 8.315 << i << '\n';
}
{
TimedSection s("cout with formatted double (width & precision on each call)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
for (int i = 0; i < iters; ++i)
{ std::cout.width(8);
std::cout.precision(3);
std::cout << text << 8.315 << i << '\n';
}
}
{
TimedSection s("printf with formatted double");
for (int i = 0; i < iters; ++i)
printf("%8.3f%i\n", 8.315, i);
}
}
Hasilnya adalah:
cout with only endl 6453.000000 ms
cout with only '\n' 125.000000 ms
printf with only '\n' 156.000000 ms
cout with string constant and endl 6937.000000 ms
cout with string constant and '\n' 1391.000000 ms
printf with string constant and '\n' 3391.000000 ms
cout with some stuff and endl 9672.000000 ms
cout with some stuff and '\n' 7296.000000 ms
printf with some stuff and '\n' 12235.000000 ms
cout with formatted double (width & precision once) 7906.000000 ms
cout with formatted double (width & precision on each call) 9141.000000 ms
printf with formatted double 3312.000000 ms
endljauh lebih efisien daripada '\n'?
endlflush buffer, dan \ntidak, meskipun saya tidak yakin ini alasan mengapa.
Saya ingin menunjukkan bahwa jika Anda ingin bermain dengan utas di C ++, jika Anda menggunakan coutAnda bisa mendapatkan beberapa hasil yang menarik.
Pertimbangkan kode ini:
#include <string>
#include <iostream>
#include <thread>
using namespace std;
void task(int taskNum, string msg) {
for (int i = 0; i < 5; ++i) {
cout << "#" << taskNum << ": " << msg << endl;
}
}
int main() {
thread t1(task, 1, "AAA");
thread t2(task, 2, "BBB");
t1.join();
t2.join();
return 0;
}
// g++ ./thread.cpp -o thread.out -ansi -pedantic -pthread -std=c++0x
Sekarang, hasilnya datang semua dikocok. Itu dapat menghasilkan hasil yang berbeda juga, coba jalankan beberapa kali:
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
Anda dapat menggunakannya printfuntuk memperbaikinya, atau Anda dapat menggunakannya mutex.
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
Selamat bersenang-senang!
threads tidak membuat output menjadi gila. Saya baru saja mereproduksi dan menemukan keduanya xyzdan ABCdalam output. Tidak ada mangling b / w ABCsebagai ABABAB.
coutkerjanya 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 menunjukkan AAAdan BBB. Tolong perbaiki, karena sekarang ini membingungkan.
cout<< "Hello";
printf("%s", "Hello");
Keduanya digunakan untuk mencetak nilai. Mereka memiliki sintaks yang sama sekali berbeda. C ++ memiliki keduanya, C hanya memiliki printf.
Saya ingin mengatakan bahwa kurangnya ekstensibilitas printftidak 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 menggunakan printfseperti ini:
Foo bar;
...;
printf("%s",bar);
bisa dimungkinkan, jika Foo membebani operator yang baik. Atau jika Anda membuat metode yang bagus. Singkatnya, printfsama mudahnya dengan coutsaya.
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 gunakan putchar('\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(karena printfada std::string::c_str(), tetapi untuk scanf?)
Karena printfsaya 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 %nformatter: "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(dan scanf) 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 yang std::stringtidak didukung. Kita harus melalui char*sebelum memberikannya kepada printf(dengan std::string::c_str()jika kita ingin membaca, tetapi bagaimana menulis?)
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"
couttidak mengembalikan apa-apa karena itu objek, bukan fungsi. operator<<mengembalikan sesuatu (biasanya operan kirinya, tetapi nilai palsu jika ada kesalahan). Dan dalam arti apakah printfpanggilan "atomik"?
printf("%s\n",7);
%sadalah ?
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 buruk printf. Alat analisis statis dapat menangkap banyak masalah ini.
printftidak melakukan pengetikan, saya tidak pernah menggunakan kompiler yang tidak memperingatkan saya tentang kesalahan ketik dengan printf...
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:
kopi =
gula panas = tidak ada
susu = payudara
mac = AA: BB: CC: DD: EE: FF
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:
char coffee[10], sugar[10], milk[10];
unsigned char mac[6];
/* Initialize those things here. */
FILE * f = fopen("a.txt", "wt");
fprintf(f, "coffee=%s\nsugar=%s\nmilk=%s\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n", coffee, sugar, milk, mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);
fclose(f);
Program C ++:
//Everything else is identical except:
std::ofstream f("a.txt", std::ios::out);
f << "coffee=" << coffee << "\n";
f << "sugar=" << sugar << "\n";
f << "milk=" << milk << "\n";
f << "mac=" << (int)mac[0] << ":"
<< (int)mac[1] << ":"
<< (int)mac[2] << ":"
<< (int)mac[3] << ":"
<< (int)mac[4] << ":"
<< (int)mac[5] << endl;
f.close();
Saya melakukan yang terbaik untuk memoles mereka sebelum saya memutarkan keduanya 100.000 kali. Inilah hasilnya:
Program C:
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
Program C ++:
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
Ukuran file objek:
C - 2,092 bytes
C++ - 3,272 bytes
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.
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.methodsintaks 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.
printfadalah fungsi sedangkan coutvariabel.
printfadalah fungsi, tetapi printf()merupakan panggilan fungsi =)