Yanıtlar:
Bu sorudaki herkesin , soru sadece farklar sorsa bile, std::cout
bundan daha iyi olduğunu iddia ettiğine şaşırdım printf
. Şimdi, bir fark var - std::cout
C ++ ve printf
C (ancak, C ++ 'da hemen hemen her şey gibi kullanabilirsiniz ). Şimdi, burada dürüst olacağım; ikisi de printf
vestd::cout
avantajları var.
std::cout
genişletilebilir. İnsanların şunu söyleyeceğini biliyorumprintf
genişletilebilir , ancak bu tür bir uzantı C standardında belirtilmedi (bu nedenle standart olmayan özellikler kullanmak zorunda kalacaksınız - ancak standart olmayan ortak özellik bile mevcut değil) ve bu uzantılar bir harftir (bu nedenle mevcut bir biçimle çakışmak kolaydır).
Bunun aksine printf
, std::cout
tamamen operatörün aşırı yüklenmesine bağlıdır, bu nedenle özel formatlarla ilgili bir sorun yoktur - tek yapmanız gereken std::ostream
ilk argüman olarak bir alt program ve ikinci olarak da türünüzü tanımlamaktır . Bu nedenle, ad alanı sorunları yoktur - bir sınıfınız olduğu sürece (bir karakterle sınırlı değildir), çalışabilirsiniz.std::ostream
bunun için aşırı yükleme .
Ancak, birçok insanın uzatmak isteyeceğinden şüphe duyuyorum ostream
(dürüst olmak gerekirse, bu uzantıları yapmak kolay olsa bile nadiren gördüm). Ancak, ihtiyacınız varsa burada.
Kolayca fark edileceği üzere; hem printf
ve std::cout
farklı bir sözdizimi kullanın. printf
desen dizesi ve değişken uzunluklu bağımsız değişken listelerini kullanarak standart işlev sözdizimini kullanır. Aslında, printf
C'nin onlara sahip olmasının bir nedeni - printf
formatlar onlar olmadan kullanılamayacak kadar karmaşık. Ancak, std::cout
farklı bir API kullanır -operator <<
kendisini döndüren API.
Genellikle bu, C versiyonunun daha kısa olacağı anlamına gelir, ancak çoğu durumda önemli olmayacaktır. Çok sayıda argüman yazdırdığınızda fark fark edilir. Error 2: File not found.
Hata numarası varsayarak ve açıklamasının yer tutucu olduğunu varsayarak, böyle bir şey yazmanız gerekiyorsa , kod şöyle görünür. Her iki örnek de aynı şekilde çalışır ( std::endl
tamponu temizler).
printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;
Bu çok çılgın görünmese de (sadece iki kat daha uzun), argümanları gerçekten yazdırdığınızda, yalnızca yazdırmak yerine, daha da çılgınlaşıyor. Örneğin, böyle bir şeyin basılması 0x0424
çılgınca. Bu, std::cout
karıştırma durumu ve gerçek değerlerden kaynaklanır. Hiç std::setfill
bir tür bir tür (tabii C ++ dışında) olacağını bir dil görmedim . printf
argümanları ve gerçek türü açıkça ayırır. Gerçekten (çok fazla gürültü içerdiği printf
için) iostream
sürümüne kıyasla (şifreli görünüyor olsa bile) sürümünü korumayı tercih ederim .
printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;
İşte burada printf
yalanların gerçek avantajı . printf
Biçim dizesi ... iyi bir dizedir. Bu, operator <<
istismarına kıyasla tercüme edilmeyi gerçekten kolaylaştırır iostream
. gettext()
İşlevin çevirdiğini ve göstermek istediğinizi varsayarsak Error 2: File not found.
, daha önce gösterilen biçim dizesinin çevirisini almak için kod şöyle görünür:
printf(gettext("Error %d: %s.\n"), id, errors[id]);
Şimdi, hata numarasının açıklamadan sonra olduğu Fictionish diline çevirdiğimizi varsayalım. Çevrilen dize şöyle görünür %2$s oru %1$d.\n
. Şimdi, C ++ ile nasıl yapılır? Hiçbir fikrim yok. Çeviri amacıyla geçebileceğiniz iostream
yapıları ya da bir şeyi sahte printf
yapabilirsiniz gettext
. Tabii ki, $
C standardı değil, ama bence kullanmak o kadar yaygın ki.
C'nin çok sayıda tamsayı türü vardır ve C ++ da öyle. std::cout
size kolları her türlü iken, printf
bir tam sayı tipine bağlı olarak, belirli bir sözdizimi gerektirir (tamsayı olmayan türleri vardır, ancak, pratikte kullanımı yalnızca tamsayı olmayan türü printf
olan const char *
(Cı-dize, kullanılarak elde edilebilir to_c
yöntemin std::string
)). Örneğin, yazdırmak için size_t
size kullanımına ihtiyaç %zd
iken, int64_t
kullanarak gerektirecektir %"PRId64"
. Tablolara http://en.cppreference.com/w/cpp/io/c/fprintf ve http://en.cppreference.com/w/cpp/types/integer adresinden ulaşılabilir .
\0
Çünkü printf
C ++ dizeleri aksine kullanımları C dizeleri, belirli hileler olmadan boş karakter baskı yapamaz. Bazı durumlarda kullanmak mümkündür %c
ile'\0'
açıkça bir hack olsa, bir argüman olarak.
Güncelleme: O iostream
kadar yavaş çıkıyor ki , genellikle sabit sürücünüzden daha yavaştır (programınızı dosyaya yönlendirirseniz). stdio
Çok sayıda veri çıkarmanız gerekirse ile senkronizasyonu devre dışı bırakmak yardımcı olabilir. Performans gerçek bir endişe ise (STDOUT'a birkaç satır yazmak yerine),printf
.
Herkes performansı önemsediğini düşünüyor, ancak kimse bunu ölçmek için rahatsız etmiyor. Cevabım, G / Ç'nin her ne şekilde olursa olsun darboğaz olduğu printf
ya da iostream
. Bu derleme hızlı bir bakış ( derleyici seçeneğini kullanarak clang ile derlenmiş) daha hızlı printf
olabileceğini düşünüyorum -O3
. Hata örneğimi varsayarsak, örnek, printf
örnekten daha az çağrı yapar cout
. Bu int main
şununla 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:
İki dizenin ve 2
(sayı) printf
argüman olarak aktarıldığını kolayca fark edebilirsiniz . Bu kadar; başka bir şey yok. Karşılaştırma için, bu iostream
montaj için derlenmiştir. Hayır, satır içi yoktur; her operator <<
çağrı, başka bir argüman kümesiyle başka bir çağrı anlamına gelir.
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:
Ancak, dürüst olmak gerekirse, G / Ç zaten darboğaz olduğu için bu hiçbir şey ifade etmiyor. Daha iostream
hızlı olmadığını göstermek istedim çünkü “güvenli”. Çoğu C uygulaması printf
, hesaplanmış goto kullanarak formatlar uygular , bu nedenle printf
derleyicinin farkında olmasa bile olabildiğince hızlıdır printf
(bazı olmadıklarından değil - bazı derleyiciler printf
belirli durumlarda optimize edebilir - sabit dize bitişi \n
genellikleputs
) .
Neden miras almak istediğini bilmiyorum ostream
, ama umrumda değil. Bu da mümkün FILE
.
class MyFile : public FILE {}
Doğru, değişken uzunluklu bağımsız değişken listelerinin güvenliği yoktur, ancak bu önemli değildir, çünkü popüler C derleyicileri printf
uyarıları etkinleştirirseniz biçim dizesiyle ilgili sorunları algılayabilir . Aslında, Clang bunu uyarıları etkinleştirmeden yapabilir.
$ 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
, bu da qsort
(2 kez) ile karşılaştırıldığında bir şekilde şaşırtıcı derecede hızlıdır . yürütülebilir boyutun maliyeti).
Gönderen C ++ SSS :
[15.1]
<iostream>
Geleneksel yerine neden kullanmalıyım<cstdio>
?Tip güvenliğini artırın, hataları azaltın, genişletilebilirliğe izin verin ve kalıtım sağlayın.
printf()
tartışmasız bir şekilde kırılmaz vescanf()
hataya eğilimli olmasına rağmen yaşanabilir, ancak her ikisi de C ++ I / O'nun yapabilecekleri ile sınırlıdır. C ++ I / O (<<
ve kullanarak>>
), C'ye (printf()
ve kullanarakscanf()
) göre:
- Daha güvenli tip:
<iostream>
I / O'd olan nesnenin türü derleyici tarafından statik olarak bilinir. Buna karşılık,<cstdio>
türleri dinamik olarak anlamak için "%" alanlarını kullanır.- Daha az hata eğilimi: İle
<iostream>
Gerçek nesnelerin I / O'd ile tutarlı olması gereken gereksiz "%" belirteçleri yoktur. Fazlalık kaldırıldığında bir sınıf hata kaldırılır.- Genişletilebilir: C ++
<iostream>
mekanizması, yeni kullanıcı tanımlı türlerin mevcut kodu bozmadan I / O'd olmasını sağlar. Herkesin aynı anda yeni uyumsuz "%" alanlarını ekleyerek olsaydı kaos düşününprintf()
vescanf()
?!- Devralınabilen: C ++
<iostream>
mekanizmasıstd::ostream
ve gibi gerçek sınıflardan oluşturulmuşturstd::istream
. Aksine<cstdio>
s'FILE*
, bu gerçek sınıfları ve dolayısıyla devredilebilir. Bu, akış gibi görünen ve hareket eden, ancak istediğiniz tuhaf ve harika şeyleri yapan, kullanıcı tanımlı başka şeylere sahip olabileceğiniz anlamına gelir. Otomatik olarak tanımadığınız kullanıcılar tarafından yazılmış G / Ç kodu satırlarını kullanırsınız ve "genişletilmiş akış" sınıfınızı bilmeleri gerekmez.
Öte yandan, printf
tercih kullanmadan haklı olabilir, önemli ölçüde daha hızlı olduğu cout
içinde çok özel ve sınırlı durumlarda. Daima önce profil yapın. (Örneğin, bkz. Http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout /)
printf()
de genişletilebilir olması gerekiyor. Kısmındaki "printf kancaları" Bkz udrepper.livejournal.com/20948.html
printf
böyle bir yeteneği yok. Taşınabilir olmayan kütüphane mekanizmaları, iostreams'in tamamen standartlaştırılmış genişletilebilirliğiyle neredeyse aynı seviyede değildir.
İnsanlar genellikle bunun printf
çok daha hızlı olduğunu iddia eder . Bu büyük ölçüde bir efsanedir. Aşağıdaki sonuçlarla test ettim:
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
Sonuç: yalnızca yeni satırlar istiyorsanız printf
; aksi takdirde cout
neredeyse hızlı veya daha hızlıdır. Daha fazla detay bulunabilir bloguma .
Açıkça söylemek gerekirse, iostream
s'nin her zamankinden daha iyi olduğunu söylemeye çalışmıyorum printf
; Sadece bazı yaygın, yanıltıcı varsayımlara dayanan vahşi bir tahmin değil, gerçek verilere dayalı bilinçli bir karar vermeniz gerektiğini söylemeye çalışıyorum.
Güncelleme: İşte test için kullandığım kodun tamamı. g++
Herhangi bir ek seçenek olmadan derlenmiştir ( -lrt
zamanlama hariç ).
#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()
ve std::ostream
olduğu eski çıkış tek bir çağrı tüm bağımsız değişkenler ise std::ostream
doğurur her biri için ayrı bir arama <<
. Test sadece bir argüman ve yeni bir satır çıkarır, bu yüzden farkı göremezsiniz.
printf
çeşitli biçimlendirme belirteçleri için yardımcı işlevlere kapak altında çok fazla çağrı yapabilir ... ya da bu korkunç bir monolitik işlevdir. Ve yine, inlining nedeniyle, hızda hiç bir fark yaratmamalıdır.
sprintf
veya fprintf
ve stringstream
yafstream
.
Ve alıntı yapıyorum :
Yüksek düzeyde terimlerle, ana farklar tip güvenliği (cstdio'da yoktur), performans (çoğu iostreams uygulaması cstdio'dan daha yavaştır) ve genişletilebilirliktir (iostreams, özel çıktı hedeflerine ve kullanıcı tanımlı türlerin kesintisiz çıktısına izin verir).
Bunlardan biri stdout'a baskı yapan bir fonksiyondur. Diğeri, çeşitli üye işlevlerini ve operator<<
bu baskının stdout'a aşırı yüklenmesini sağlayan bir nesnedir . Numaralandırabileceğim çok daha fazla fark var, ama neyin peşinde olduğundan emin değilim.
Benim için, 'printf' yerine 'cout' yapmamı sağlayacak gerçek farklılıklar:
1) << operatörü sınıflarım için aşırı yüklenebilir.
2) Cout için çıkış akışı kolayca bir dosyaya değiştirilebilir: (: kopyala yapıştır :)
#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) Özellikle birçok parametremiz olduğunda cout'u daha okunabilir buluyorum.
Bir sorun ile cout
biçimlendirme seçenekleri olduğunu. Verileri (hassasiyet, gerekçe vb.) Biçimlendirmek printf
daha kolaydır.
printf
ile değiştirerek de bir dosyaya fprintf
...
Burada aksi belirtilmedikçe önemli bulduğum iki nokta:
1) cout
STL'yi kullanmıyorsanız çok fazla bagaj taşır. Nesne dosyanıza iki kat daha fazla kod ekler printf
. Bu da geçerlidir string
ve kendi string kütüphanemi kullanma eğilimimin ana sebebi budur.
2) talihsiz bulduğum cout
aşırı yüklenmiş <<
operatörleri kullanıyor . Ayrıca,<<
Operatörün amacına uygun olarak sola kayma olabilir (sola kaydırma). Şahsen, amaçlanan kullanımlarına teğet amaçlarla operatörleri aşırı yüklemeyi sevmiyorum.
Alt satır: Eğer zaten STL kullanıyorsanız cout
(ve string
) kullanacağım . Aksi takdirde bundan kaçınma eğilimindeyim.
İlkellerde muhtemelen hangisini kullandığınız önemli değildir. Yararlı hale geldiğini söylüyorum, karmaşık nesneler çıkarmak istediğinizde.
Örneğin, bir sınıfınız varsa,
#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;
}
Şimdi yukarıdakiler o kadar da harika görünmeyebilir, ancak diyelim ki bunu kodunuzda birden fazla yerde çıkarmanız gerekiyor. Sadece bu değil, diyelim ki bir alan eklediniz "int d". Cout ile, sadece bir yerde değiştirmeniz gerekir. Bununla birlikte, printf ile, muhtemelen birçok yerde değiştirmek zorunda kalacaksınız ve sadece bunu değil, kendinize hangilerinin çıktı vereceğini hatırlatmalısınız.
Bununla birlikte, cout ile, kodunuzun bakımı ile harcanan birçok zamanı azaltabilirsiniz ve sadece "Bir şey" nesnesini yeni bir uygulamada yeniden kullanırsanız, çıktı için gerçekten endişelenmenize gerek yoktur.
Tabii ki bakım tutmak için biraz daha iyi bir şey yazabilirsiniz:
#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;
}
Ve biraz daha fazla cout ve printf testi, daha fazla test yapmak istiyorsa (Visual Studio 2008, yürütülebilir sürüm): 'double' testi ekledi:
#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);
}
}
Sonuç:
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
daha az verimli '\n'
?
endl
tamponu temizler çünkü inanıyorum , ve \n
değil, her ne kadar bunun kesin nedeni olduğundan emin değilim.
C ++ 'da konu ile oynamak istiyorsanız, kullanırsanız cout
bazı ilginç sonuçlar elde edebileceğinizi belirtmek isterim .
Bu kodu düşünün:
#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
Şimdi, çıktı hepsi karışık. Farklı sonuçlar da verebilir, birkaç kez çalıştırmayı deneyin:
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
Doğru yapmak için kullanabilirsiniz printf
veya kullanabilirsiniz mutex
.
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
İyi eğlenceler!
thread
s çıkış fındık gitmek yapmayın. Ben sadece çoğaltılabilir ve her ikisi de bulundu xyz
ve ABC
çıktıda. S / b ABC
gibi mangling yoktu ABABAB
.
cout
Konuları ile nasıl çalıştığını bilmiyorum , ama gösterdiğiniz kodun bu çıktıları almak için kullandığınız biri olmadığından eminim. Kodunuz "ABC"
, iş parçacığı 1 ve "xyz"
iş parçacığı 2 için dizeyi geçirir , ancak çıktınız AAA
ve öğelerini gösterir BBB
. Lütfen düzeltin, çünkü şu anda kafa karıştırıcı.
cout<< "Hello";
printf("%s", "Hello");
Her ikisi de değerleri yazdırmak için kullanılır. Tamamen farklı bir sözdizimine sahipler. C ++ her ikisine de sahiptir, C yalnızca printf'ye sahiptir.
Genişletilebilirlik eksikliğinin printf
tamamen doğru olmadığını söylemek istiyorum :
C'de bu doğrudur. Ancak C'de gerçek sınıflar yoktur.
C ++ 'da, döküm operatörünü aşırı yüklemek mümkündür, bu nedenle bir char*
operatörü aşırı yüklemek ve şöyle kullanmak printf
:
Foo bar;
...;
printf("%s",bar);
Foo iyi operatöre aşırı yüklenirse mümkün olabilir. Veya iyi bir yöntem yaptıysanız. Kısacası, printf
benim kadar genişletilebilir cout
.
C ++ akışları için görebildiğim teknik argüman (genel olarak ... sadece cout değil):
Typesafety. (Ve bu arada, '\n'
kullandığım tek bir baskı yapmak istersem putchar('\n')
... Bir böceği öldürmek için nükleer bomba kullanmayacağım.).
Öğrenmesi daha basit. (öğrenmek için "karmaşık" parametreler yok, sadece kullanımı <<
ve >>
operatörler)
Doğal Work std::string
(için printf
orada std::string::c_str()
, ama için scanf
?)
For printf
I bkz:
Daha kolay veya en azından daha kısa (yazılı karakterler açısından) karmaşık biçimlendirme. Benim için çok daha okunabilir (sanırım lezzet meselesi).
İşlevin ne yaptığının daha iyi kontrolü (Yazılan %n
karakter sayısını ve biçimlendiriciyi döndürün: "Hiçbir şey yazdırılmadı. Bağımsız değişken, şimdiye kadar yazılan karakter sayısının depolandığı imzalı bir int'e bir işaretçi olmalıdır." ( Printf'den - C ++ Referansı )
Daha iyi hata ayıklama olanakları. Son argümanla aynı nedenle.
Kişisel tercihlerim printf
(ve scanf
) işlevlerine gider , çünkü kısa çizgileri severim ve metin yazdırmayla ilgili yazım sorunlarının önlenmesi gerçekten zor değildir. C stili işlevlerle çektiğim tek şey std::string
desteklenmiyor. Biz geçmek zorunda char*
vermeden önce printf
(ile std::string::c_str()
biz okumak istiyorsanız ama nasıl yazılır?)
char*
kullanılmayacak.
char*
yaşamların nerede ve ne kadar süreyle ve kullanıcı tanımlı tehlikeleri gibi bazı ciddi sorunları göz ardı eder. zımni dökümler.
Diğer farklar: "printf" bir tamsayı değeri (yazdırılan karakter sayısına eşit) döndürür ve "cout" hiçbir şey döndürmez
Ve.
cout << "y = " << 7;
atomik değildir.
printf("%s = %d", "y", 7);
atomiktir.
cout yazım denetimi yapar, printf yapmaz.
Hiçbir iostream eşdeğeri yok "% d"
cout
hiçbir şey döndürmez, çünkü bu bir işlev değil, bir nesnedir. operator<<
bir şey döndürür (normalde sol işlenen, ancak bir hata varsa yanlış bir değer). Ve hangi anlamda printf
"atom" denir?
printf("%s\n",7);
%s
dır-dir ?
printf
% s argümanı boş sonlandırılmış dize geçerli bir işaretçi olması gerekir. '7' bellek aralığı (işaretçi) genellikle geçerli değildir; bir segmentasyon hatası şanslı olabilir. Bazı sistemlerde, '7' bir konsola çok fazla çöp yazdırabilir ve program durmadan önce bir gün boyunca ona bakmanız gerekir. Başka bir deyişle, bu kötü bir şey printf
. Statik analiz araçları bu sorunların çoğunu yakalayabilir.
printf
typechecking yapmazken, ben asla tür hataları hakkında beni uyarmayan bir derleyici kullanmadım printf
...
TL; DR: Bu dahil olmak üzere çevrimiçi rastgele yorumlara güvenmeden önce oluşturulan makine kodu boyutu , performans , okunabilirlik ve kodlama süresi ile ilgili olarak her zaman kendi araştırmanızı yapın .
Ben uzman değilim. Performans sorunları nedeniyle gömülü sistemlerde C ++ kullanmaktan nasıl kaçınmamız gerektiğinden bahseden iki iş arkadaşına kulak misafiri oldum. Yeterince ilginç, gerçek bir proje görevine dayanan bir kıyaslama yaptım.
Bahsedilen görevde, RAM'e bir yapılandırma yazmak zorunda kaldık. Gibi bir şey:
kahve = sıcak
şeker =
süt yok = meme
mac = AA: BB: CC: DD: EE: FF
İşte kıyaslama programlarım (Evet, OP'nin fprintf () değil, printf () hakkında sorduğunu biliyorum. Özü yakalamaya çalışın ve bu arada OP'nin fprintf () bağlantısını yine de gösteriyor.)
C programı:
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);
C ++ programı:
//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();
Her ikisini de 100.000 kez döngüye sokmadan önce cilalamak için elimden geleni yaptım. Sonuçlar burada:
C programı:
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
C ++ programı:
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
Nesne dosya boyutu:
C - 2,092 bytes
C++ - 3,272 bytes
Sonuç: Benim çok özel olarak platformun çok özel olan, işlemci çok spesifik bir sürümünü çalıştıran, Linux çekirdeğinin bir çok özel sürümüyle derlenmiş bir program çalıştırmak için, GCC çok özel başarmak amacıyla, görevi diyebilirim C ++ yaklaşımı daha uygundur çünkü çok daha hızlı çalışır ve daha iyi okunabilirlik sağlar. Öte yandan, C küçük bir ayak izi sunuyor, bence, program boyutu endişe duymadığımız için neredeyse hiçbir şey ifade etmiyor.
Hatırlayın, YMMV.
Ben programcı değilim ama insan faktörü mühendisi oldum. Bir programlama dilinin öğrenmesi, anlaması ve kullanması kolay olduğunu düşünüyorum, bu da basit ve tutarlı bir dil yapısına sahip olmasını gerektiriyor. Tüm diller sembolik olmasına rağmen, özünde, keyfi olarak, sözleşmeler vardır ve bunları takip etmek dili öğrenmeyi ve kullanmayı kolaylaştırır.
C ++ 'da ve fonksiyon (parametre) olarak yazılan diğer dillerde çok sayıda fonksiyon vardır, başlangıçta bilgisayar öncesi dönemde matematikte fonksiyonel ilişkiler için kullanılan bir sözdizimi. printf()
bu sözdizimini izler ve C ++ yazarları dosyaları okumak ve yazmak için mantıksal olarak farklı bir yöntem oluşturmak isteselerdi, benzer bir sözdizimi kullanarak farklı bir işlev oluşturabilirlerdi.
Python'da elbette oldukça standart object.method
sözdizimini, yani variablename.print'i kullanarak yazdırabiliriz , çünkü değişkenler nesnedir, ancak C ++ 'da değildir.
Ben cout sözdizimine düşkün değilim çünkü << operatörü herhangi bir kurala uymuyor. Bir yöntem veya işlevdir, yani bir parametre alır ve ona bir şey yapar. Ancak, matematiksel bir karşılaştırma operatörü gibi yazılmıştır. Bu, insan faktörleri açısından zayıf bir yaklaşımdır.
printf
bir işlevken cout
bir değişkendir.
printf
bir işlevdir, ancak printf()
bir işlev çağrısıdır =)