जवाबों:
मुझे आश्चर्य है कि इस सवाल में हर कोई ऐसा दावा करता std::cout
है printf
, जो बेहतर है , भले ही सवाल सिर्फ मतभेद के लिए पूछा गया हो। अब, एक अंतर है - std::cout
सी ++ है, और printf
सी है (हालांकि, आप इसे सी ++ में उपयोग कर सकते हैं, जैसे सी के अलावा लगभग कुछ भी)। अब, मैं यहाँ ईमानदार रहूँगा; दोनों printf
और std::cout
उनके फायदे हैं।
std::cout
एक्स्टेंसिबल है। मुझे पता है कि लोग कहेंगे कि printf
यह एक्स्टेंसिबल भी है, लेकिन इस तरह के विस्तार का सी मानक में उल्लेख नहीं किया गया है (इसलिए आपको गैर-मानक सुविधाओं का उपयोग करना होगा - लेकिन सामान्य गैर-मानक सुविधा भी मौजूद नहीं है), और ऐसे एक्सटेंशन एक अक्षर हैं (इसलिए पहले से मौजूद प्रारूप के साथ संघर्ष करना आसान है)।
इसके विपरीत printf
, std::cout
ऑपरेटर ओवरलोडिंग पर पूरी तरह से निर्भर करता है, इसलिए कस्टम प्रारूपों के साथ कोई समस्या नहीं है - आप जो भी करते हैं वह std::ostream
पहले तर्क के रूप में एक उप-अंक को परिभाषित करता है और आपके प्रकार को दूसरे के रूप में लेता है । जैसे, कोई नाम स्थान की समस्याएं नहीं हैं - जब तक आपके पास एक वर्ग (जो कि एक चरित्र तक सीमित नहीं है), तो आप std::ostream
इसके लिए ओवरलोडिंग का काम कर सकते हैं ।
हालांकि, मुझे संदेह है कि बहुत से लोग विस्तार करना चाहेंगे ostream
(ईमानदार होना, मैंने शायद ही कभी ऐसे एक्सटेंशन देखे हों, भले ही वे बनाने में आसान हों)। हालाँकि, यह यहाँ है अगर आपको इसकी आवश्यकता है।
यह आसानी से देखा जा सकता है, दोनों printf
और std::cout
विभिन्न सिंटैक्स का उपयोग करें। printf
पैटर्न स्ट्रिंग और चर-लंबाई तर्क सूचियों का उपयोग करके मानक फ़ंक्शन सिंटैक्स का उपयोग करता है। दरअसल, printf
एक कारण है कि सी उनके पास है - printf
प्रारूप उनके बिना उपयोग किए जाने के लिए बहुत जटिल हैं। हालाँकि, std::cout
एक अलग API का उपयोग करता है - aoperator <<
एपीआई जो खुद को वापस करता है।
आम तौर पर, इसका मतलब है कि सी संस्करण छोटा होगा, लेकिन ज्यादातर मामलों में यह मायने नहीं रखेगा। जब आप कई तर्क छापते हैं तो अंतर ध्यान देने योग्य होता है। यदि आपको Error 2: File not found.
त्रुटि संख्या मानकर कुछ लिखना है , और उसका विवरण प्लेसहोल्डर है, तो कोड इस तरह दिखेगा। दोनों उदाहरण पहचान का काम करते हैं (ठीक है, की तरह, std::endl
वास्तव में बफर फ्लश करता है)।
printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;
हालांकि यह बहुत अधिक पागल नहीं है (यह सिर्फ दो बार लंबा है), चीजें अधिक पागल हो जाती हैं जब आप वास्तव में तर्क देते हैं, केवल उन्हें मुद्रित करने के बजाय। उदाहरण के लिए, किसी चीज़ की छपाई 0x0424
सिर्फ पागल है। यह std::cout
राज्य और वास्तविक मूल्यों के मिश्रण के कारण होता है । मैंने कभी ऐसी भाषा नहीं देखी, जहां कोई चीज std::setfill
एक प्रकार की हो (सी ++ के अलावा, निश्चित रूप से)। printf
स्पष्ट रूप से तर्क और वास्तविक प्रकार को अलग करता है। मैं वास्तव printf
में इसके संस्करण की तुलना में इसके संस्करण को बनाए रखना पसंद करूंगा (भले ही यह किसी प्रकार का गुप्त हो) iostream
(जैसा कि इसमें बहुत अधिक शोर है)।
printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;
यहीं से printf
झूठ का असली फायदा होता है। printf
प्रारूप स्ट्रिंग अच्छी तरह से एक स्ट्रिंग है ...। इसका operator <<
दुरुपयोग करने की तुलना में अनुवाद करना वास्तव में आसान है iostream
। यह मानते हुए कि gettext()
फ़ंक्शन अनुवाद करता है, और आप दिखाना चाहते हैं Error 2: File not found.
, पहले दिखाए गए प्रारूप स्ट्रिंग का अनुवाद पाने के लिए कोड इस तरह दिखाई देगा:
printf(gettext("Error %d: %s.\n"), id, errors[id]);
अब, मान लेते हैं कि हम फिक्शनिश में अनुवाद करते हैं, जहां वर्णन के बाद त्रुटि संख्या है। अनुवादित स्ट्रिंग की तरह दिखेगा %2$s oru %1$d.\n
। अब, इसे C ++ में कैसे करें? खैर, मुझे कोई पता नहीं है। मुझे लगता है कि आप नकली बना सकते हैं iostream
जो निर्माण करता है printf
जिसे आप gettext
अनुवाद के उद्देश्यों के लिए पास कर सकते हैं , या कुछ कर सकते हैं । बेशक, $
सी मानक नहीं है, लेकिन यह इतना आम है कि मेरी राय में उपयोग करना सुरक्षित है।
C में बहुत सारे पूर्णांक प्रकार हैं, और इसलिए C ++ है। std::cout
हैंडल आप के लिए सभी प्रकार के हैं, जबकि printf
एक पूर्णांक प्रकार के आधार पर विशिष्ट वाक्यविन्यास की आवश्यकता है (वहाँ गैर पूर्णांक प्रकार के होते हैं, लेकिन केवल गैर पूर्णांक प्रकार आप के साथ व्यवहार में उपयोग करेगा printf
है const char *
(सी स्ट्रिंग, का उपयोग कर प्राप्त किया जा सकता to_c
की विधि std::string
))। उदाहरण के लिए, प्रिंट करने के लिए size_t
, आपको उपयोग करने की आवश्यकता है %zd
, जबकि उपयोग करने int64_t
की आवश्यकता होगी %"PRId64"
। टेबल http://en.cppreference.com/w/cpp/io/c/fprintf और http://en.cppreference.com/w/cpp/types/integer पर उपलब्ध हैं ।
\0
चूँकि printf
C ++ स्ट्रिंग्स के विपरीत C स्ट्रिंग्स का उपयोग करता है, इसलिए यह विशिष्ट ट्रिक्स के बिना NUL बाइट प्रिंट नहीं कर सकता है। कुछ मामलों में यह तर्क के रूप में उपयोग %c
करना संभव है '\0'
, हालांकि यह स्पष्ट रूप से हैक है।
अपडेट: यह पता चला है कि iostream
यह इतना धीमा है कि यह आमतौर पर आपकी हार्ड ड्राइव की तुलना में धीमा है (यदि आप अपने प्रोग्राम को फ़ाइल में रीडायरेक्ट करते हैं)। stdio
यदि आप बहुत सारे डेटा का उत्पादन करने की आवश्यकता है, तो इसके साथ सिंक्रनाइज़ेशन अक्षम करना मदद कर सकता है। यदि प्रदर्शन एक वास्तविक चिंता है (जैसा कि एसटीडीयूएसटी के लिए कई लाइनों को लिखने का विरोध किया गया है), बस उपयोग करें printf
।
हर कोई सोचता है कि वे प्रदर्शन के बारे में परवाह करते हैं, लेकिन कोई भी इसे मापने के लिए परेशान नहीं करता है। मेरा जवाब यह है कि मैं / हे वैसे भी अड़चन है, कोई फर्क नहीं पड़ता कि आप उपयोग करते हैं printf
या iostream
। मुझे लगता है कि असेंबली में एक त्वरित नज़र से तेज printf
हो सकता है ( -O3
संकलक विकल्प का उपयोग करके क्लैंग के साथ संकलित )। मेरे त्रुटि उदाहरण को मानते हुए, printf
उदाहरण उदाहरण से कम कॉल करता है cout
। यह इसके int main
साथ है 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:
आप आसानी से देख सकते हैं कि दो तार, और 2
(संख्या) को printf
तर्क के रूप में धकेल दिया जाता है। यह इसके बारे में; और कुछ नहीं। तुलना के लिए, यह iostream
विधानसभा के लिए संकलित है। नहीं, कोई अशुद्धि नहीं है; हर एक operator <<
कॉल का अर्थ है एक और कॉल के साथ दूसरा तर्क।
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:
हालांकि, ईमानदार होने के लिए, इसका मतलब कुछ भी नहीं है, क्योंकि I / O वैसे भी अड़चन है। मैं सिर्फ यह दिखाना चाहता था कि iostream
यह तेज नहीं है क्योंकि यह "टाइप सेफ" है। अधिकांश सी कार्यान्वयन printf
कम्प्यूटेड गोटो का उपयोग करके प्रारूपों को लागू करते हैं, इसलिए printf
यह जितनी तेजी से हो सकता है, यहां तक कि संकलक के बारे में पता किए बिना भी printf
(ऐसा नहीं है कि वे नहीं हैं - कुछ कंपाइलर printf
कुछ मामलों में अनुकूलित कर सकते हैं - लगातार स्ट्रिंग समाप्त होने के साथ \n
आमतौर पर अनुकूलित होता हैputs
) ।
मुझे नहीं पता कि आप वारिस क्यों बनना चाहेंगे ostream
, लेकिन मुझे परवाह नहीं है। इसके साथ FILE
भी संभव है।
class MyFile : public FILE {}
सही है, परिवर्तनशील लंबाई तर्क सूचियों की कोई सुरक्षा नहीं है, लेकिन इससे कोई फर्क नहीं पड़ता, क्योंकि लोकप्रिय सी कंपाइलर printf
चेतावनी को सक्षम करने पर प्रारूप स्ट्रिंग के साथ समस्याओं का पता लगा सकते हैं । वास्तव में, क्लैंग चेतावनी को सक्षम किए बिना ऐसा कर सकता है।
$ 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
, जो किसी भी qsort
समय (2 बार) की तुलना में आश्चर्यजनक रूप से तेज़ है ) निष्पादन योग्य आकार की लागत)।
से सी ++ पूछे जाने वाले प्रश्न :
[१५.१] मुझे
<iostream>
पारंपरिक के बजाय क्यों इस्तेमाल करना चाहिए<cstdio>
?प्रकार की सुरक्षा बढ़ाएं, त्रुटियों को कम करें, एक्स्टेंसिबिलिटी की अनुमति दें, और विरासत प्रदान करें।
printf()
यकीनन टूटा नहीं है, औरscanf()
शायद त्रुटि प्रवण होने के बावजूद रहने योग्य है, हालांकि दोनों सी ++ आई / ओ के संबंध में सीमित हैं। C ++ I / O (उपयोग करना<<
और>>
), C के सापेक्ष (उपयोग करनाprintf()
औरscanf()
):
- अधिक प्रकार-सुरक्षित:
<iostream>
संकलक द्वारा I / O'd के प्रकार को वस्तु के रूप में जाना जाता है। इसके विपरीत,<cstdio>
गतिशील रूप से प्रकारों का पता लगाने के लिए "%" फ़ील्ड का उपयोग करता है।- कम त्रुटि प्रवण: इसके साथ
<iostream>
, कोई अनावश्यक "%" टोकन नहीं हैं जिन्हें वास्तविक वस्तुओं के अनुरूप होना चाहिए I / O'd। अतिरेक को हटाने से त्रुटियों का एक वर्ग दूर हो जाता है।- एक्स्टेंसिबल: सी ++
<iostream>
तंत्र नए उपयोगकर्ता-परिभाषित प्रकारों को मौजूदा कोड को तोड़ने के बिना I / O'd होने की अनुमति देता है। अराजकता की कल्पना करो अगर हर कोई एक साथ नए असंगत "%" फ़ील्ड जोड़ रहा थाprintf()
औरscanf()
!- इनहेरिटेबल: सी ++
<iostream>
तंत्र को वास्तविक वर्गों जैसेstd::ostream
और से बनाया गया हैstd::istream
। विपरीत<cstdio>
हैFILE*
, इन वास्तविक वर्गों और इसलिए दाय हैं। इसका मतलब है कि आपके पास अन्य उपयोगकर्ता-परिभाषित चीजें हो सकती हैं जो धाराओं की तरह दिखती हैं और कार्य करती हैं, फिर भी जो कुछ भी अजीब और अद्भुत चीजें आप चाहते हैं। आपको स्वचालित रूप से उन उपयोगकर्ताओं द्वारा लिखी गई I / O कोड की पंक्तियों का उपयोग करने की अनुमति मिलती है जिन्हें आप जानते भी नहीं हैं, और उन्हें आपके "विस्तारित स्ट्रीम" वर्ग के बारे में जानने की आवश्यकता नहीं है।
दूसरी ओर, printf
वरीयता में इसे प्रयोग का औचित्य साबित हो सकता है, काफी तेजी है cout
में बहुत विशिष्ट और सीमित मामलों। हमेशा पहले प्रोफ़ाइल। (देखें, उदाहरण के लिए, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout /)
printf()
वह भी एक्स्टेंसिबल माना जाता है। Udrepper.livejournal.com/20948.html
printf
में ऐसी कोई क्षमता नहीं है। गैर-पोर्टेबल लाइब्रेरी तंत्र मुश्किल से एक ही स्तर पर हैं क्योंकि iostreams की पूरी तरह से मानकीकृत एक्स्टेंसिबिलिटी है।
लोग अक्सर दावा करते हैं कि printf
यह बहुत तेज है। यह काफी हद तक एक मिथक है। मैंने अभी इसका परीक्षण किया, निम्नलिखित परिणाम:
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
निष्कर्ष: यदि आप केवल नए अंक चाहते हैं, तो उपयोग करें printf
; अन्यथा, cout
लगभग उतना ही तेज है, या इससे भी तेज है। अधिक विवरण मेरे ब्लॉग पर पाए जा सकते हैं ।
स्पष्ट होने के लिए, मैं यह कहने की कोशिश नहीं कर रहा हूं कि iostream
एस हमेशा से बेहतर होते हैं printf
; मैं केवल यह कहना चाह रहा हूं कि आपको वास्तविक डेटा के आधार पर एक सूचित निर्णय लेना चाहिए, न कि कुछ सामान्य, भ्रामक धारणा के आधार पर एक जंगली अनुमान।
अद्यतन: यहाँ पूर्ण कोड मैं परीक्षण के लिए प्रयोग किया जाता है। g++
बिना किसी अतिरिक्त विकल्प ( -lrt
समय के अलावा ) के साथ संकलित ।
#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()
और std::ostream
है कि पूर्व outputs एक ही कॉल में सभी तर्कों जबकि std::ostream
incurs प्रत्येक के लिए एक अलग कॉल <<
। परीक्षण केवल एक तर्क और एक नई-लाइन का उत्पादन करता है, यही कारण है कि आप अंतर नहीं देख सकते हैं।
printf
विभिन्न स्वरूपण विनिर्देशक के लिए सहायक कार्यों के लिए कवर के तहत बहुत सारी कॉल कर सकते हैं ... या, यह एक राक्षसी अखंड कार्य है। और फिर, inlining के कारण, यह गति में बिल्कुल फर्क नहीं करना चाहिए।
sprintf
या fprintf
और stringstream
या fstream
।
और मैं बोली :
उच्च स्तर की शर्तों में, मुख्य अंतर प्रकार की सुरक्षा है (cstdio के पास यह नहीं है), प्रदर्शन (अधिकांश iostreams कार्यान्वयन cstdio वाले की तुलना में धीमे हैं) और एक्स्टेंसिबिलिटी (iostreams कस्टम आउटपुट लक्ष्य और उपयोगकर्ता परिभाषित प्रकारों के निर्बाध उत्पादन की अनुमति देता है)।
एक ऐसा फ़ंक्शन है जो प्रिंटआउट करता है। दूसरा एक ऐसा ऑब्जेक्ट है जो कई सदस्य कार्यों और operator<<
उस प्रिंट के ओवरलोड को स्टडआउट प्रदान करता है। ऐसे और भी कई अंतर हैं जिन्हें मैं समझ सकता हूं, लेकिन मुझे यकीन नहीं है कि आप आखिर हैं क्या।
मेरे लिए, वास्तविक मतभेद जो मुझे 'प्रिंटफ' के बजाय 'कॉट' के लिए जाने देंगे:
1) << ऑपरेटर को मेरी कक्षाओं के लिए अधिभारित किया जा सकता है।
2) cout के लिए आउटपुट स्ट्रीम को आसानी से फाइल में बदला जा सकता है: (: कॉपी पेस्ट :)
#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) मुझे cout अधिक पठनीय लगता है, खासकर जब हमारे पास कई पैरामीटर हैं।
एक समस्याcout
स्वरूपण विकल्पों के साथ है। डेटा (सटीक, उचित, आदि) को प्रारूपित करना printf
आसान है।
printf
से एक फ़ाइल के साथ इसे बदलने के लिए बदल सकते हैं fprintf
...
दो बिंदु अन्यथा यहाँ उल्लेख नहीं है कि मुझे महत्वपूर्ण लगता है:
1) cout
यदि आप पहले से ही एसटीएल का उपयोग नहीं कर रहे हैं तो बहुत सारा सामान ले जाते हैं। यह आपके ऑब्जेक्ट फ़ाइल के रूप में के रूप में दो बार के रूप में अधिक कोड जोड़ता है printf
। यह भी सच है string
, और यही एक बड़ी वजह है कि मैं अपनी खुद की स्ट्रिंग लाइब्रेरी का उपयोग करता हूं।
2) cout
ओवरलोडेड <<
ऑपरेटरों का उपयोग करता है , जो मुझे दुर्भाग्यपूर्ण लगता है। यदि आप भी उपयोग कर रहे हैं तो यह भ्रम को जोड़ सकता है<<
ऑपरेटर को उसके इच्छित उद्देश्य (बाईं ओर शिफ्ट) । मैं व्यक्तिगत रूप से अपने इच्छित उपयोग के लिए ठोस उद्देश्यों के लिए ऑपरेटरों को ओवरलोड करना पसंद नहीं करता।
नीचे पंक्ति: यदि मैं पहले से ही एसटीएल का उपयोग कर रहा हूं, तो cout
(और string
) का उपयोग करूंगा । अन्यथा, मैं इससे बचता हूं।
आदिम के साथ, यह शायद पूरी तरह से कोई फर्क नहीं पड़ता कि आप किसका उपयोग करते हैं। मैं कहता हूं कि यह तब उपयोगी हो जाता है जब आप जटिल वस्तुओं का उत्पादन करना चाहते हैं।
उदाहरण के लिए, यदि आपके पास एक वर्ग है,
#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;
}
अब ऊपर यह सब बहुत अच्छा नहीं लग सकता है, लेकिन मान लीजिए कि आपको इसे अपने कोड में कई स्थानों पर आउटपुट करना होगा। इतना ही नहीं, मान लीजिए कि आप एक फ़ील्ड "int d" जोड़ते हैं। कूट के साथ, आपको इसे केवल एक बार बदलना होगा। हालाँकि, प्रिंटफ के साथ, आपको इसे संभवतः बहुत सी जगहों पर बदलना होगा और इतना ही नहीं, आपको खुद को यह याद दिलाना होगा कि आउटपुट के लिए कौन-कौन से हैं।
उस के साथ, cout के साथ, आप अपने कोड के रखरखाव के साथ बिताए गए समय को बहुत कम कर सकते हैं और इतना ही नहीं यदि आप किसी नए एप्लिकेशन में ऑब्जेक्ट "समथिंग" का दोबारा उपयोग करते हैं, तो आपको वास्तव में आउटपुट के बारे में चिंता करने की ज़रूरत नहीं है।
बेशक आप रख-रखाव के लिए "कुछ" थोड़ा बेहतर लिख सकते हैं:
#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;
}
और कॉट बनाम प्रिंटफ के एक बिट विस्तारित परीक्षण ने 'डबल' का एक परीक्षण जोड़ा, अगर कोई और परीक्षण करना चाहता है (विजुअल स्टूडियो 2008, निष्पादन योग्य का रिलीज़ संस्करण):
#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);
}
}
परिणाम है:
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
इतना कम कुशल क्यों है '\n'
?
endl
बफर को फ्लश \n
करता है , और नहीं करता है, हालांकि मुझे यकीन नहीं है कि यह निश्चित रूप से कारण है।
मैं यह बताना चाहता हूं कि यदि आप C ++ में थ्रेड के साथ खेलना चाहते हैं, यदि आप उपयोग cout
करते हैं तो आप कुछ दिलचस्प परिणाम प्राप्त कर सकते हैं।
इस कोड पर विचार करें:
#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
अब, आउटपुट में सभी फेरबदल होते हैं। यह विभिन्न परिणाम भी दे सकता है, कई बार निष्पादित करने का प्रयास करें:
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
आप printf
इसे सही करने के लिए उपयोग कर सकते हैं , या आप उपयोग कर सकते हैं mutex
।
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
मज़े करो!
thread
आउटपुट गो नट्स नहीं बनाता है। मैं तो बस बनाए गए और दोनों पाया xyz
और ABC
उत्पादन में। के ABC
रूप में ख / w नहीं लड़ रहा था ABABAB
।
cout
थ्रेड्स के साथ कैसे काम किया जाता है, लेकिन मैं यह सुनिश्चित करने के लिए जानता हूं कि जो कोड आप दिखा रहे हैं वह वह नहीं है जो आप उन आउटपुट को प्राप्त करने के लिए उपयोग करते हैं। आपका कोड "ABC"
थ्रेड 1 के लिए और "xyz"
थ्रेड 2 के लिए पास करता है, लेकिन आपका आउटपुट दिखाता है AAA
और BBB
। कृपया इसे ठीक करें, क्योंकि अभी यह भ्रामक है।
cout<< "Hello";
printf("%s", "Hello");
दोनों का उपयोग मूल्यों को प्रिंट करने के लिए किया जाता है। उनके पास पूरी तरह से अलग वाक्यविन्यास है। C ++ में दोनों हैं, C में केवल प्रिंटफ है।
मैं कहना चाहूंगा कि विस्तार की कमी printf
पूरी तरह से सच नहीं है:
सी में, यह सच है। लेकिन सी में, कोई वास्तविक कक्षाएं नहीं हैं।
C ++ में, कास्ट ऑपरेटर को ओवरलोड करना संभव है, इसलिए, char*
ऑपरेटर को ओवरलोड करना और printf
इस तरह का उपयोग करना :
Foo bar;
...;
printf("%s",bar);
संभव है, अगर फू अच्छे ऑपरेटर को अधिभारित करता है। या अगर आपने एक अच्छा तरीका बनाया है। संक्षेप में, मेरे लिए printf
जितना एक्स्टेंसिबल cout
है।
तकनीकी तर्क मैं C ++ स्ट्रीम के लिए देख सकता हूं (सामान्य रूप से ... न केवल cout।) हैं:
Typesafety। (और, वैसे, अगर मैं एक एकल प्रिंट का '\n'
उपयोग करना चाहता हूं putchar('\n')
... मैं एक कीट को मारने के लिए एक परमाणु बम का उपयोग नहीं करूंगा।)
सीखने में सरल। (कोई "जटिल" पैरामीटर सीखने के लिए नहीं, बस उपयोग करने के लिए <<
और >>
ऑपरेटरों)
मूल रूप से std::string
( printf
वहाँ है std::string::c_str()
, लेकिन के लिए scanf
) के साथ काम करते हैं ?
के लिए printf
मैं देख रहा हूँ:
आसान या कम से कम कम (लिखित वर्णों की अवधि में) जटिल स्वरूपण। मेरे लिए और अधिक पठनीय, स्वाद की बात (मुझे लगता है)।
फ़ंक्शन ने जो बनाया है उसका बेहतर नियंत्रण (लौटें जहां लिखे गए वर्ण हैं और वहां %n
फ़ॉर्मेटर है: "कुछ भी मुद्रित नहीं है। तर्क पर हस्ताक्षर किए गए इंटेंट के लिए सूचक होना चाहिए, जहां अब तक लिखे गए वर्णों की संख्या संग्रहीत है।" ( प्रिंटफ़ से) - C ++ संदर्भ )
बेहतर डिबगिंग की संभावनाएं। अंतिम तर्क के समान कारण के लिए।
मेरी व्यक्तिगत प्राथमिकताएं printf
(और scanf
) कार्यों में जाती हैं, मुख्यतः क्योंकि मुझे छोटी लाइनें पसंद हैं, और क्योंकि मुझे नहीं लगता कि मुद्रण पाठ पर टाइप की समस्याएं वास्तव में बचने के लिए कठिन हैं। सी-स्टाइल फ़ंक्शंस के साथ केवल एक चीज जो मुझे पसंद आती है, std::string
वह समर्थित नहीं है। हमें char*
इसे देने से पहले गुजरना होगा printf
( std::string::c_str()
यदि हम पढ़ना चाहते हैं, लेकिन कैसे लिखना है?)
char*
उपयोग नहीं किया जाएगा।
char*
और कितने समय तक रहता है, और उपयोगकर्ता-परिभाषित के खतरों को नजरअंदाज करता है। निहितार्थ।
अधिक अंतर: "प्रिंटफ" एक पूर्णांक मान देता है (मुद्रित वर्णों की संख्या के बराबर) और "कटआउट" उन्हें वापस नहीं करता है
तथा।
cout << "y = " << 7;
परमाणु नहीं है।
printf("%s = %d", "y", 7);
परमाणु है।
cout टाइपकास्ट करता है, प्रिंटफ नहीं करता है।
के बराबर कोई iostream नहीं है "% d"
cout
कुछ वापस नहीं करता क्योंकि यह एक वस्तु है, एक फ़ंक्शन नहीं है। operator<<
कुछ वापस करता है (आम तौर पर इसके बाएं ऑपरेंड, लेकिन अगर कोई त्रुटि है तो एक गलत मूल्य)। और किस अर्थ में printf
"परमाणु" कहा जाता है?
printf("%s\n",7);
%s
है ?
printf
% s तर्क में शून्य समाप्त स्ट्रिंग के लिए एक वैध सूचक होना चाहिए। मेमोरी रेंज '7' (एक पॉइंटर) आमतौर पर मान्य नहीं है; एक विभाजन दोष भाग्यशाली हो सकता है। कुछ प्रणालियों पर, '7' बहुत सारे कचरे को एक कंसोल में प्रिंट कर सकता है और आपको प्रोग्राम बंद होने से पहले एक दिन के लिए इसे देखना होगा। दूसरे शब्दों में, यह एक बुरी बात है printf
। स्थैतिक विश्लेषण उपकरण इनमें से कई मुद्दों को पकड़ सकते हैं।
printf
टाइपकास्ट नहीं करता है, मैंने कभी भी एक कंपाइलर का उपयोग नहीं किया है जो मुझे टाइप त्रुटियों के बारे में चेतावनी नहीं देता printf
...
टीएल; डीआर: हमेशा अपने स्वयं के अनुसंधान करते हैं, इस एक सहित यादृच्छिक टिप्पणियों पर भरोसा करने से पहले उत्पन्न मशीन कोड आकार , प्रदर्शन , पठनीयता और कोडिंग समय के संबंध में ।
मैं कोई विशेषज्ञ नहीं हूँ। मैं सिर्फ दो सहकर्मियों के बारे में बात करने के लिए हुआ, हम प्रदर्शन के मुद्दों के कारण एम्बेडेड सिस्टम में C ++ का उपयोग करने से कैसे बचना चाहिए। खैर, काफी दिलचस्प, मैंने एक वास्तविक परियोजना कार्य के आधार पर एक बेंचमार्क किया।
उक्त कार्य में, हमें RAM में कुछ विन्यास लिखना था। कुछ इस तरह:
कॉफी = गर्म
चीनी =
दूध नहीं = स्तन
मैक = एए: बीबी: सीसी: डीडी: ईई: एफएफ
यहां मेरे बेंचमार्क प्रोग्राम हैं (हां, मुझे पता है कि ओपी ने प्रिंटफ (), फ़र्प्रिंटफ़ () के बारे में पूछा था) सार पर कब्जा करने की कोशिश करें और वैसे भी, ओपी के लिंक वैसे भी फ़िंटप्रिंट () पर इंगित करते हैं।
सी कार्यक्रम:
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 ++ प्रोग्राम:
//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();
इससे पहले कि मैं उन दोनों को 100,000 बार लूप करूं, मैंने उन्हें चमकाने की पूरी कोशिश की। यहाँ परिणाम हैं:
सी कार्यक्रम:
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
C ++ प्रोग्राम:
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
ऑब्जेक्ट फ़ाइल का आकार:
C - 2,092 bytes
C++ - 3,272 bytes
निष्कर्ष: मेरे बहुत ही विशिष्ट मंच पर , एक बहुत ही विशिष्ट प्रोसेसर के साथ , लिनक्स कर्नेल के एक बहुत ही विशिष्ट संस्करण को चलाने के लिए, एक प्रोग्राम को चलाने के लिए, जिसे बहुत विशिष्ट कार्य को पूरा करने के लिए, जीसीसी के एक बहुत ही विशिष्ट संस्करण के साथ संकलित किया गया है , मैं कहूंगा C ++ दृष्टिकोण अधिक उपयुक्त है क्योंकि यह काफी तेजी से चलता है और बेहतर पठनीयता प्रदान करता है। दूसरी ओर, सी छोटे पदचिह्न प्रदान करता है, मेरी राय में, इसका मतलब लगभग कुछ भी नहीं है क्योंकि कार्यक्रम का आकार हमारी चिंता का विषय नहीं है।
रिमेम्बर, YMMV।
मैं एक प्रोग्रामर नहीं हूं, लेकिन मैं एक मानव कारक इंजीनियर रहा हूं। मुझे लगता है कि एक प्रोग्रामिंग भाषा को सीखना, समझना और उपयोग करना आसान होना चाहिए, और इसके लिए यह आवश्यक है कि इसकी एक सरल और सुसंगत भाषाई संरचना हो। यद्यपि सभी भाषाएं प्रतीकात्मक हैं और इस प्रकार, इसके मूल में, मनमाने तरीके से, कन्वेंशन हैं और इनका अनुसरण करने से भाषा सीखना और उपयोग करना आसान हो जाता है।
C ++ और फ़ंक्शन (पैरामीटर) के रूप में लिखी जाने वाली अन्य भाषाओं में बड़ी संख्या में फ़ंक्शन हैं, एक सिंटैक्स जो मूल रूप से पूर्व-कंप्यूटर युग में गणित में कार्यात्मक संबंधों के लिए उपयोग किया गया था। printf()
इस सिंटैक्स का अनुसरण करता है और यदि C ++ के लेखक फ़ाइलों को पढ़ने और लिखने के लिए कोई तार्किक रूप से अलग विधि बनाना चाहते हैं, तो वे एक समान सिंटैक्स का उपयोग करके एक अलग फ़ंक्शन बना सकते हैं।
अजगर में हम निश्चित रूप से काफी मानक object.method
वाक्यविन्यास, अर्थात varablename.print का उपयोग करके प्रिंट कर सकते हैं , क्योंकि चर ऑब्जेक्ट हैं, लेकिन C ++ में वे नहीं हैं।
मैं cout सिंटैक्स का शौकीन नहीं हूं क्योंकि << ऑपरेटर किसी भी नियम का पालन नहीं करता है। यह एक विधि या कार्य है, अर्थात यह एक पैरामीटर लेता है और इसे कुछ करता है। हालाँकि यह लिखा है कि यह एक गणितीय तुलना ऑपरेटर था। यह मानवीय कारकों के दृष्टिकोण से एक खराब दृष्टिकोण है।
printf
एक फ़ंक्शन है जबकि cout
एक चर है।
printf
एक फ़ंक्शन है, लेकिन printf()
एक फ़ंक्शन कॉल है =)