Jawaban:
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 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::ostream
danstd::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, printf
secara signifikan lebih cepat, yang dapat membenarkan menggunakannya dalam preferensi untuk cout
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 /)
printf()
ini juga seharusnya bisa diperluas. Lihat "printf hooks" di udrepper.livejournal.com/20948.html
printf
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:
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, 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 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 -lrt
waktunya).
#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::ostream
adalah bahwa mantan menampilkan semua argumen dalam satu panggilan tunggal sedangkan std::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
atau fprintf
dan stringstream
atau 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 cout
adalah opsi format. Memformat data (presisi, justifikasi, dll.) Lebih printf
mudah.
printf
ke file juga dengan menggantinya dengan fprintf
...
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 Anda printf
. Ini juga berlaku untuk string
, 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
(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
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:
#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 printf
untuk 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!
thread
s tidak membuat output menjadi gila. Saya baru saja mereproduksi dan menemukan keduanya xyz
dan ABC
dalam output. Tidak ada mangling b / w ABC
sebagai ABABAB
.
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 menunjukkan AAA
dan 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 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 menggunakan printf
seperti ini:
Foo bar;
...;
printf("%s",bar);
bisa dimungkinkan, jika Foo membebani operator yang baik. Atau jika Anda membuat metode yang bagus. Singkatnya, printf
sama mudahnya dengan cout
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 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 printf
ada std::string::c_str()
, tetapi untuk scanf
?)
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
(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::string
tidak 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"
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 apakah printf
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 buruk printf
. Alat analisis statis dapat menangkap banyak masalah ini.
printf
tidak 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.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.
printf
adalah fungsi sedangkan cout
variabel.
printf
adalah fungsi, tetapi printf()
merupakan panggilan fungsi =)