C ++ में 'Printf' बनाम 'cout'


जवाबों:


332

मुझे आश्चर्य है कि इस सवाल में हर कोई ऐसा दावा करता 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 पर उपलब्ध हैं ।

आप NUL बाइट नहीं छाप सकते, \0

चूँकि printfC ++ स्ट्रिंग्स के विपरीत 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);
     ^

18
आप कहते हैं कि I / O वैसे भी अड़चन है। जाहिर है कि आपने कभी उस धारणा का परीक्षण नहीं किया है। मैं अपने आप को उद्धृत करता हूं: "दूसरी ओर, 75.3 एमबी / एस पर आईओस्ट्रीम संस्करण, हार्ड डिस्क को रखने के लिए डेटा को तेजी से बफर नहीं कर सकता। यह बुरा है, और यह अभी तक कोई वास्तविक काम भी नहीं कर रहा है। मैं मुझे लगता है कि मुझे बहुत अधिक उम्मीदें हैं जब मैं कहता हूं कि मेरा I / O पुस्तकालय मेरे डिस्क नियंत्रक को संतृप्त करने में सक्षम होना चाहिए। "
बेन वोइगट

4
@BenVoigt: मैं मानता हूं, मैं जब संभव हो तो C ++ से बचने की कोशिश करता हूं। मैंने इसका बहुत उपयोग करने की कोशिश की, लेकिन यह अधिक कष्टप्रद था, और अन्य प्रोग्रामिंग भाषा की तुलना में कम रखरखाव योग्य था जिसका मैंने उपयोग किया था। मेरे लिए C ++ से बचने का यह एक और कारण है - यह भी तेज़ नहीं है (यह भी iostream नहीं है - संपूर्ण C ++ लाइब्रेरी अधिकांश कार्यान्वयन में धीमा है, शायद अपवाद के साथ std::sort, जो किसी भी qsortसमय (2 बार) की तुलना में आश्चर्यजनक रूप से तेज़ है ) निष्पादन योग्य आकार की लागत)।
कोनराड बोरोस्की

3
यहां किसी ने भी cout का उपयोग करते समय समानांतर वातावरण में मुद्दों का उल्लेख नहीं किया है।
निकोलस हैमिल्टन

9
आपका प्रदर्शन तर्क कोई मायने नहीं रखता है। आपके प्रोग्राम में अधिक असेंबली का मतलब यह नहीं है कि प्रोग्राम धीमा हो जाएगा, क्योंकि आप उन सभी कोड के लिए लेखांकन नहीं कर रहे हैं जो प्रिंटफ फ़ंक्शन करता है, जो बहुत सारे कोड है। मेरी राय में, के साथ कॉट को अनुकूलित करना संभव है << ऑपरेटर प्रिंटफ से बहुत बेहतर है, क्योंकि कंपाइलर चर और स्वरूपण की बेहतर समझ बना सकता है।
इग्नास २५२६ २६'१५

18
मुझे इस जवाब के बारे में बहुत सारी बातें पसंद हैं, लेकिन शायद मेरा पसंदीदा हिस्सा है "हर कोई सोचता है कि वे प्रदर्शन के बारे में परवाह करते हैं, लेकिन कोई भी इसे मापने के लिए परेशान नहीं करता है।"
काइल स्ट्रैंड

203

से सी ++ पूछे जाने वाले प्रश्न :

[१५.१] मुझे <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 /)


2
दूसरी ओर, FastFormat पुस्तकालय ( fastformat.org ) है, जो एक ही बार में टाइप-सेफ्टी, एक्सप्रेसिटी और प्रदर्शन प्रदान करता है। (ऐसा नहीं है कि मैंने इसे अभी तक कोशिश की ...)
xtofl

3
@Marcelo शायद इसलिए क्योंकि यह एक अच्छा सारांश है, सब कुछ उद्धृत किया गया है। स्वरूपण ... हाँ, यह बहुत बुरा है। मुझे खुद को तय करना चाहिए था, लेकिन ऐसा प्रतीत होता है कि अन्य (स्वयं शामिल) ने इसका ध्यान रखा, जो निश्चित रूप से, केवल रोने की तुलना में अधिक रचनात्मक है।
मिकेग

2
जैसे-जैसे देर होती है, printf()वह भी एक्स्टेंसिबल माना जाता है। Udrepper.livejournal.com/20948.html
मैक्सिम

4
@MaximYegorushkin: मानक printfमें ऐसी कोई क्षमता नहीं है। गैर-पोर्टेबल लाइब्रेरी तंत्र मुश्किल से एक ही स्तर पर हैं क्योंकि iostreams की पूरी तरह से मानकीकृत एक्स्टेंसिबिलिटी है।
बेन वोइग्ट

4
"दूसरी ओर, प्रिंटफ काफी तेज है" प्रिंटफ भी क्लीनर और उपयोग करने में आसान है, यही कारण है कि मैं जब संभव हो तो कॉट से बचता हूं।
फ्लोरेसेंटग्रीन 5

43

लोग अक्सर दावा करते हैं कि 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);
    }
}

5
आपके अंकों में प्रिंटफ़ आसानी से (बहुसंख्यक मामलों) को मारता है। मुझे आश्चर्य है कि जब आप परिपूर्ण होने की बात करते हैं तो आप कॉट का उपयोग करने की सलाह क्यों देते हैं। हालांकि मैं मानता हूं कि यथार्थवादी मामलों में भी perf अलग नहीं है ..
mishal153

3
@ mishal153: मैं केवल यह कहने की कोशिश कर रहा हूं कि प्रदर्शन बहुत अलग नहीं है, इसलिए आमतौर पर "कभी काउंट का उपयोग न करें क्योंकि यह वाया धीमा है" की सामान्य रूप से सुनाई देने वाली सलाह सादी बेवकूफी है। ध्यान दें कि cout में टाइप-सेफ्टी का स्पष्ट लाभ है, और अक्सर पठनीयता भी। (फ्लोइंग-पॉइंट फॉर्मेटिंग विद आईस्ट्रीम भयानक है ...)
थॉमस

35
के बीच महत्वपूर्ण अंतर printf()और std::ostreamहै कि पूर्व outputs एक ही कॉल में सभी तर्कों जबकि std::ostreamincurs प्रत्येक के लिए एक अलग कॉल <<। परीक्षण केवल एक तर्क और एक नई-लाइन का उत्पादन करता है, यही कारण है कि आप अंतर नहीं देख सकते हैं।
मैक्सिम इगोरुशिन

12
कंपाइलर इन कॉल को इनलाइन करने में सक्षम होना चाहिए। इसके अलावा, printfविभिन्न स्वरूपण विनिर्देशक के लिए सहायक कार्यों के लिए कवर के तहत बहुत सारी कॉल कर सकते हैं ... या, यह एक राक्षसी अखंड कार्य है। और फिर, inlining के कारण, यह गति में बिल्कुल फर्क नहीं करना चाहिए।
थॉमस

4
आपने अपना टर्मिनल समय पर दिया। का प्रयोग करें sprintfया fprintfऔर stringstreamया fstream
बेन वोइगट

41

और मैं बोली :

उच्च स्तर की शर्तों में, मुख्य अंतर प्रकार की सुरक्षा है (cstdio के पास यह नहीं है), प्रदर्शन (अधिकांश iostreams कार्यान्वयन cstdio वाले की तुलना में धीमे हैं) और एक्स्टेंसिबिलिटी (iostreams कस्टम आउटपुट लक्ष्य और उपयोगकर्ता परिभाषित प्रकारों के निर्बाध उत्पादन की अनुमति देता है)।


विशेष रूप से यूनिक्स पर जहां पोसिक्स के साथ आप कभी नहीं जानते हैं कि वास्तव में टाइपराइफ में से किसी एक का आकार क्या है, इसलिए आपको बहुत सारे कलाकारों की आवश्यकता होती है या 99% कार्यक्रमों के रूप में आप इसे% d के साथ जोखिम में डालते हैं। % Z को C99 के साथ आने से पहले भी एक लंबा समय लगता था। लेकिन time_t / off_t के लिए सही प्रारूप निर्देश के लिए खोज जारी है।
लोथर

30

एक ऐसा फ़ंक्शन है जो प्रिंटआउट करता है। दूसरा एक ऐसा ऑब्जेक्ट है जो कई सदस्य कार्यों और operator<<उस प्रिंट के ओवरलोड को स्टडआउट प्रदान करता है। ऐसे और भी कई अंतर हैं जिन्हें मैं समझ सकता हूं, लेकिन मुझे यकीन नहीं है कि आप आखिर हैं क्या।


12

मेरे लिए, वास्तविक मतभेद जो मुझे 'प्रिंटफ' के बजाय 'कॉट' के लिए जाने देंगे:

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आसान है।


1
यह अच्छा है। मैं कैसे जान सकता हूं कि किसी विदेशी पुस्तकालय के धागे में कोई भी इस तरह से वैश्विक संशोधन को संशोधित नहीं कर सकता है?
vp_arth 17

1
आप आसानी printfसे एक फ़ाइल के साथ इसे बदलने के लिए बदल सकते हैं fprintf...
CoffeeTableEspresso

5

दो बिंदु अन्यथा यहाँ उल्लेख नहीं है कि मुझे महत्वपूर्ण लगता है:

1) coutयदि आप पहले से ही एसटीएल का उपयोग नहीं कर रहे हैं तो बहुत सारा सामान ले जाते हैं। यह आपके ऑब्जेक्ट फ़ाइल के रूप में के रूप में दो बार के रूप में अधिक कोड जोड़ता है printf। यह भी सच है string, और यही एक बड़ी वजह है कि मैं अपनी खुद की स्ट्रिंग लाइब्रेरी का उपयोग करता हूं।

2) coutओवरलोडेड <<ऑपरेटरों का उपयोग करता है , जो मुझे दुर्भाग्यपूर्ण लगता है। यदि आप भी उपयोग कर रहे हैं तो यह भ्रम को जोड़ सकता है<< ऑपरेटर को उसके इच्छित उद्देश्य (बाईं ओर शिफ्ट) । मैं व्यक्तिगत रूप से अपने इच्छित उपयोग के लिए ठोस उद्देश्यों के लिए ऑपरेटरों को ओवरलोड करना पसंद नहीं करता।

नीचे पंक्ति: यदि मैं पहले से ही एसटीएल का उपयोग कर रहा हूं, तो cout(और string) का उपयोग करूंगा । अन्यथा, मैं इससे बचता हूं।


4

आदिम के साथ, यह शायद पूरी तरह से कोई फर्क नहीं पड़ता कि आप किसका उपयोग करते हैं। मैं कहता हूं कि यह तब उपयोगी हो जाता है जब आप जटिल वस्तुओं का उत्पादन करना चाहते हैं।

उदाहरण के लिए, यदि आपके पास एक वर्ग है,

#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 के साथ, आप अपने कोड के रखरखाव के साथ बिताए गए समय को बहुत कम कर सकते हैं और इतना ही नहीं यदि आप किसी नए एप्लिकेशन में ऑब्जेक्ट "समथिंग" का दोबारा उपयोग करते हैं, तो आपको वास्तव में आउटपुट के बारे में चिंता करने की ज़रूरत नहीं है।


इसके अलावा, प्रदर्शन के बारे में बात करने के लिए, मैं कहूंगा कि यदि आपका आवेदन प्रदर्शन के लिए बनाया गया है, तो आपको कुछ भी आउटपुट नहीं करना चाहिए। एसटीडी के लिए किसी भी तरह का आउटपुट महंगा और धीमा होता है। मैं कहता हूं कि आपको इसे और केवल आउटपुट से बचना चाहिए जब ऐसा करना पूरी तरह से आवश्यक हो।
डैनियल

ध्यान रखें कि आपकी कक्षा में निजी सदस्य हो सकते हैं जिन्हें आप बाहर से इतनी आसानी से एक्सेस नहीं कर सकते। आउटपुट ऑपरेटर के साथ, आपके पास वास्तव में एक स्थान होता है, जिसे आपकी कक्षा में मित्र होने की आवश्यकता होती है, और अब आप इसे कहीं भी आउटपुट कर सकते हैं, यहां तक ​​कि कोड के बारे में भी आपको पता नहीं था।
14

2

बेशक आप रख-रखाव के लिए "कुछ" थोड़ा बेहतर लिख सकते हैं:

#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'?
निकोलस हैमिल्टन

1
मेरा मानना ​​है कि यह endlबफर को फ्लश \nकरता है , और नहीं करता है, हालांकि मुझे यकीन नहीं है कि यह निश्चित रूप से कारण है।
कालेब जू

यह सवाल का जवाब नहीं है, यह डैनियल और थॉमस के जवाब की तरह है ।
फैबियो का कहना है कि मोनिका

2

मैं यह बताना चाहता हूं कि यदि आप 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

मज़े करो!


2
wtf threadआउटपुट गो नट्स नहीं बनाता है। मैं तो बस बनाए गए और दोनों पाया xyzऔर ABCउत्पादन में। के ABCरूप में ख / w नहीं लड़ रहा था ABABAB
अभिनव गौनियाल

1
मुझे नहीं पता कि coutथ्रेड्स के साथ कैसे काम किया जाता है, लेकिन मैं यह सुनिश्चित करने के लिए जानता हूं कि जो कोड आप दिखा रहे हैं वह वह नहीं है जो आप उन आउटपुट को प्राप्त करने के लिए उपयोग करते हैं। आपका कोड "ABC"थ्रेड 1 के लिए और "xyz"थ्रेड 2 के लिए पास करता है, लेकिन आपका आउटपुट दिखाता है AAAऔर BBB। कृपया इसे ठीक करें, क्योंकि अभी यह भ्रामक है।
फैबियो का कहना है कि मोनिका

1
cout<< "Hello";
printf("%s", "Hello"); 

दोनों का उपयोग मूल्यों को प्रिंट करने के लिए किया जाता है। उनके पास पूरी तरह से अलग वाक्यविन्यास है। C ++ में दोनों हैं, C में केवल प्रिंटफ है।


19
... क्या? क्या तुमने कुछ मिलाया?
xtofl

1
मुद्दा तय किया। -1 क्योंकि इसमें फिक्सिंग की आवश्यकता होती है और उत्तर वांछित होने के लिए बहुत कुछ छोड़ देता है।
याकोबी

3
फ़ंक्शन के नाम उलट हो गए थे: प्रिंटआउट सिंटैक्स के साथ cout का उपयोग किया गया था, और cout सिंटैक्स के साथ printf का उपयोग किया गया था। भी स्वीकार नहीं किया जाना चाहिए था!
महमूद अल-कुद्सी

2
और कॉट का मुख्य नुकसान यह है कि यह ऑपरेटर का उपयोग करता है << जो क्रिया और बदसूरत और यकीनन ऑपरेटर दुरुपयोग है। :)
जालपा

8
हालांकि यह निश्चित रूप से सबसे अच्छा जवाब नहीं है, मुझे समझ में नहीं आता है कि कैसे स्कैटमैन को उसके जवाब के लिए केवल इसलिए दंडित किया जा रहा है क्योंकि इसे सर्वश्रेष्ठ उत्तर के रूप में चुना गया था। xbit के पास एक खराब उत्तर IMO है, लेकिन -1 वोट है। मैं यह नहीं कह रहा हूँ कि xbit को किसी भी तरह से अधिक मत दिया जाना चाहिए, लेकिन मुझे ओपी की गलती के लिए वोट स्कैटरमैन के लिए निष्पक्ष होना उचित नहीं दिख रहा है ...
Jesse

1

मैं कहना चाहूंगा कि विस्तार की कमी 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()यदि हम पढ़ना चाहते हैं, लेकिन कैसे लिखना है?)


3
कंपाइलर के पास वार्गस फ़ंक्शंस के लिए कोई प्रकार की जानकारी नहीं है, इसलिए यह वास्तविक पैरामीटर ( डिफ़ॉल्ट तर्क पदोन्नति को छोड़कर , जैसे कि मानक एकीकरण प्रचार) को परिवर्तित नहीं करेगा । 5.2.2p7 देखें। उपयोगकर्ता द्वारा परिभाषित रूपांतरण का char*उपयोग नहीं किया जाएगा।
बेन वोइग्ट

यहां तक ​​कि अगर यह काम करता है, तो यह स्प्रिंटफ एक्स्टेंसिबिलिटी का उदाहरण नहीं होगा, स्प्रिंटफ को देने के लिए सिर्फ एक चतुर हैक, जो यह अपेक्षा करता है, और यह कुछ गंभीर मुद्दों जैसे कि जहां char*और कितने समय तक रहता है, और उपयोगकर्ता-परिभाषित के खतरों को नजरअंदाज करता है। निहितार्थ।
मार्सेलो कैंटोस

1

अधिक अंतर: "प्रिंटफ" एक पूर्णांक मान देता है (मुद्रित वर्णों की संख्या के बराबर) और "कटआउट" उन्हें वापस नहीं करता है

तथा।

cout << "y = " << 7; परमाणु नहीं है।

printf("%s = %d", "y", 7); परमाणु है।

cout टाइपकास्ट करता है, प्रिंटफ नहीं करता है।

के बराबर कोई iostream नहीं है "% d"


3
coutकुछ वापस नहीं करता क्योंकि यह एक वस्तु है, एक फ़ंक्शन नहीं है। operator<<कुछ वापस करता है (आम तौर पर इसके बाएं ऑपरेंड, लेकिन अगर कोई त्रुटि है तो एक गलत मूल्य)। और किस अर्थ में printf"परमाणु" कहा जाता है?
कीथ थॉम्पसन

9
यह परमाणु बम की तरह है। printf("%s\n",7);
आर्टलेस शोर

@artlessnoise इंतजार है कि विभाजन की गलती क्यों? %sहै ?
अभिनव गौनियाल

1
वह 'परमाणु बम' कथन का बिंदु है। एक printf % s तर्क में शून्य समाप्त स्ट्रिंग के लिए एक वैध सूचक होना चाहिए। मेमोरी रेंज '7' (एक पॉइंटर) आमतौर पर मान्य नहीं है; एक विभाजन दोष भाग्यशाली हो सकता है। कुछ प्रणालियों पर, '7' बहुत सारे कचरे को एक कंसोल में प्रिंट कर सकता है और आपको प्रोग्राम बंद होने से पहले एक दिन के लिए इसे देखना होगा। दूसरे शब्दों में, यह एक बुरी बात है printf। स्थैतिक विश्लेषण उपकरण इनमें से कई मुद्दों को पकड़ सकते हैं।
आर्टलेस शोर

जबकि तकनीकी रूप से printfटाइपकास्ट नहीं करता है, मैंने कभी भी एक कंपाइलर का उपयोग नहीं किया है जो मुझे टाइप त्रुटियों के बारे में चेतावनी नहीं देता printf...
कॉफीटेबलस्प्रेसो

1

टीएल; डीआर: हमेशा अपने स्वयं के अनुसंधान करते हैं, इस एक सहित यादृच्छिक टिप्पणियों पर भरोसा करने से पहले उत्पन्न मशीन कोड आकार , प्रदर्शन , पठनीयता और कोडिंग समय के संबंध में ।

मैं कोई विशेषज्ञ नहीं हूँ। मैं सिर्फ दो सहकर्मियों के बारे में बात करने के लिए हुआ, हम प्रदर्शन के मुद्दों के कारण एम्बेडेड सिस्टम में 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 ++ अधिक पठनीय है, क्योंकि आपका उदाहरण एक सिंगल प्रिंटफ कॉल में कई लाइनें पैक करता है। यह स्वाभाविक रूप से कम पढ़ने योग्य है जिस तरह से आपने सी ++ कोड किया था, और शायद ही कभी सी में किया जाता है क्योंकि इसे पढ़ने के लिए कठिन और बनाए रखने के लिए कठिन है। एक निष्पक्ष तुलना सी प्रिंट लाइन के लिए अलग प्रिंटफ में फैल जाएगी।
maharvey67

1
@ maharvey67 यह सच है कि आपने क्या कहा। हालाँकि, मैंने C में जो उदाहरण दिया, वह प्रदर्शन के विचार में था। पहले से ही C ++ तुल्यता की तुलना में fprintf के लिए पैक-इन-वन कॉल दो सेकंड धीमा था। अगर मैं C कोड को पढ़ने योग्य बनाता तो यह और भी धीमा हो सकता था। डिस्क्लेमर: यह एक साल पहले था और मुझे याद है कि मैंने C और C ++ कोड दोनों को चमकाने की पूरी कोशिश की थी। मेरे पास अलग-अलग कॉल का कोई सबूत नहीं था कि फ़र्फ़रफ एक सिंगल कॉल से तेज़ होगा, लेकिन मैंने इसे इस तरह से करने का कारण शायद यह इंगित करता है कि यह नहीं था।
वेस्ले

0

मैं एक प्रोग्रामर नहीं हूं, लेकिन मैं एक मानव कारक इंजीनियर रहा हूं। मुझे लगता है कि एक प्रोग्रामिंग भाषा को सीखना, समझना और उपयोग करना आसान होना चाहिए, और इसके लिए यह आवश्यक है कि इसकी एक सरल और सुसंगत भाषाई संरचना हो। यद्यपि सभी भाषाएं प्रतीकात्मक हैं और इस प्रकार, इसके मूल में, मनमाने तरीके से, कन्वेंशन हैं और इनका अनुसरण करने से भाषा सीखना और उपयोग करना आसान हो जाता है।

C ++ और फ़ंक्शन (पैरामीटर) के रूप में लिखी जाने वाली अन्य भाषाओं में बड़ी संख्या में फ़ंक्शन हैं, एक सिंटैक्स जो मूल रूप से पूर्व-कंप्यूटर युग में गणित में कार्यात्मक संबंधों के लिए उपयोग किया गया था। printf()इस सिंटैक्स का अनुसरण करता है और यदि C ++ के लेखक फ़ाइलों को पढ़ने और लिखने के लिए कोई तार्किक रूप से अलग विधि बनाना चाहते हैं, तो वे एक समान सिंटैक्स का उपयोग करके एक अलग फ़ंक्शन बना सकते हैं।

अजगर में हम निश्चित रूप से काफी मानक object.methodवाक्यविन्यास, अर्थात varablename.print का उपयोग करके प्रिंट कर सकते हैं , क्योंकि चर ऑब्जेक्ट हैं, लेकिन C ++ में वे नहीं हैं।

मैं cout सिंटैक्स का शौकीन नहीं हूं क्योंकि << ऑपरेटर किसी भी नियम का पालन नहीं करता है। यह एक विधि या कार्य है, अर्थात यह एक पैरामीटर लेता है और इसे कुछ करता है। हालाँकि यह लिखा है कि यह एक गणितीय तुलना ऑपरेटर था। यह मानवीय कारकों के दृष्टिकोण से एक खराब दृष्टिकोण है।


-1

printfएक फ़ंक्शन है जबकि coutएक चर है।


6
मैंने एक रोल-बैक किया, क्योंकि उत्तर स्वयं गलत हो सकता है, फिर भी यह एक वास्तविक उत्तर है। यदि आप (सही ढंग से) सोचते हैं कि उत्तर गलत है, तो आपके पास दो विकल्प हैं: 1) एक टिप्पणी जोड़ें या 2) एक नया उत्तर जोड़ें (या दोनों)। किसी के उत्तर को इस तरह न बदलें कि यह लेखक द्वारा बताए गए उद्देश्य से पूरी तरह से अलग हो।
मार्क

1
printfएक फ़ंक्शन है, लेकिन printf()एक फ़ंक्शन कॉल है =)
vp_arth

cout एक ऑब्जेक्ट है, वेरिएबल नहीं है।
लिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.