कॉल के बाद प्रिंटफ फ्लश क्यों नहीं करता है जब तक कि प्रारूप स्ट्रिंग में कोई नई रेखा नहीं होती है?


538

printfकॉल के बाद फ्लश क्यों नहीं किया जाता है जब तक कि प्रारूप स्ट्रिंग में कोई नई रेखा नहीं है? क्या यह POSIX व्यवहार है? मैं printfहर बार तुरंत कैसे फुला सकता हूं ?


2
क्या आपने जांच की कि क्या यह किसी फ़ाइल के साथ या केवल टर्मिनलों के साथ होता है? कि हालांकि मैं उम्मीद इस पर लागू नहीं होगा एक चतुर टर्मिनल एक पृष्ठभूमि कार्यक्रम से उत्पादन अपूर्ण लाइन के लिए नहीं की सुविधा होने के लिए ध्वनि, होगा अग्रभूमि कार्यक्रम।
PypeBros

7
Cygwin बैश के तहत मैं इस एक ही दुर्व्यवहार भले ही एक नई पंक्ति दिखाई दे रही है है प्रारूप स्ट्रिंग में। यह समस्या विंडोज 7 के लिए नई है; समान स्रोत कोड ने Windows XP पर ठीक काम किया। उम्मीद के मुताबिक MS cmd.exe फ्लश हो गया। फिक्स setvbuf(stdout, (char*)NULL, _IONBF, 0)समस्या के आसपास काम करता है, लेकिन निश्चित रूप से आवश्यक नहीं होना चाहिए था। मैं MSVC ++ 2008 एक्सप्रेस का उपयोग कर रहा हूं। ~~~
स्टीव पिचर्स

9
प्रश्न के शीर्षक को स्पष्ट करने के लिए: printf(..) कोई भी फ्लशिंग नहीं करता है, यह बफ़रिंग stdoutहो सकती है जब एक नई पंक्ति (यदि यह लाइन-बफ़र्ड है) को देखकर फ़्लश हो सकता है। यह उसी तरह से प्रतिक्रिया करेगा putchar('\n');, इसलिए printf(..)इस संबंध में विशेष नहीं है। यह इसके विपरीत है cout << endl;, जिसके दस्तावेजीकरण में निस्तब्धता का उल्लेख है। Printf के प्रलेखन बिल्कुल निस्तब्धता उल्लेख नहीं है।
इवगेनी सर्गेव

1
लेखन (/ निस्तब्धता) संभावित रूप से एक महंगा ऑपरेशन है, यह संभवतः प्रदर्शन कारणों से बफर्ड है।
हन्सेनैरिक

@EvgeniSergeev: क्या इस बात पर आम सहमति है कि प्रश्न ने समस्या का गलत तरीके से निदान किया है, और जब उत्पादन में एक नई रूपरेखा आती है, तो क्या होता है ? (प्रारूप स्ट्रिंग में एक डालने का एक तरीका है, लेकिन आउटपुट में एक होने का एकमात्र तरीका नहीं है)।
बेन वोइगट

जवाबों:


701

stdoutधारा लाइन डिफ़ॉल्ट रूप से बफ़र है, इसलिए केवल प्रदर्शित करेगा क्या बफर में है के बाद यह एक नई पंक्ति तक पहुँच जाता है (या जब यह करने के लिए कहा गया है)। आपके पास तुरंत प्रिंट करने के लिए कुछ विकल्प हैं:

stderrउपयोग करने के बजाय प्रिंट करें fprintf( डिफ़ॉल्ट रूपstderr से अप्रभावित है ):

fprintf(stderr, "I will be printed immediately");

जब भी आपको इसका उपयोग करने की आवश्यकता हो तो फ्लश करें fflush:

printf("Buffered, will be flushed");
fflush(stdout); // Will now print everything in the stdout buffer

संपादित करें : नीचे एंडी रॉस की टिप्पणी से, आप उपयोग करके stdout पर बफरिंग को भी अक्षम कर सकते हैं setbuf:

setbuf(stdout, NULL);

266
या, बफ़रिंग को पूरी तरह से अक्षम करने के लिए:setbuf(stdout, NULL);
एंडी रॉस

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

5
मुझे लगता है कि मैं जोड़ना चाहिए लग रहा है: मैं बस इस सिद्धांत का परीक्षण कर रही है, और मैं लग रहा है कि का उपयोग कर setlinebuf()एक धारा है जो एक टर्मिनल के लिए निर्देशित नहीं है पर है प्रत्येक पंक्ति के अंत में निस्तब्धता।
Doddy

8
"जैसा कि शुरू में खोला गया था, मानक त्रुटि स्ट्रीम पूरी तरह से बफ़र नहीं है; मानक इनपुट और मानक आउटपुट स्ट्रीम पूरी तरह से बफ़र किए गए हैं यदि और केवल अगर धारा का निर्धारण एक इंटरैक्टिव डिवाइस को संदर्भित नहीं करने के लिए किया जा सकता है" - इस प्रश्न को देखें: stackoverflow.com / सवाल / ५२२

3
@RZZwolinski यदि यह "मुद्रण क्यों नहीं हो रहा है" का एक अच्छा कैनन उत्तर हो रहा है, तो टर्मिनल / फ़ाइल के अंतर का उल्लेख करना महत्वपूर्ण लगता है "क्या प्रिंटफ़ हमेशा एक नई पंक्ति का सामना करने पर बफर को फ्लश करता है?" सीधे इस अत्यधिक उत्कट उत्तर में, बनाम लोगों को टिप्पणियों को पढ़ने की आवश्यकता ...
HostileFork का कहना है कि विश्वास मत करो एसई

128

नहीं, यह POSIX व्यवहार नहीं है, यह के आईएसओ व्यवहार (ठीक है, यह है POSIX व्यवहार लेकिन केवल insofar के रूप में वे आईएसओ के अनुरूप)।

यदि मानक डिवाइस को इंटरएक्टिव डिवाइस के रूप में संदर्भित किया जा सकता है, तो मानक आउटपुट बफ़र किया जाता है, अन्यथा यह पूरी तरह से बफ़र्ड है। तो ऐसी स्थितियाँ हैं, जहाँ printfसे बाहर नहीं निकलेगा, भले ही उसे बाहर भेजने के लिए एक नई रेखा मिले, जैसे:

myprog >myfile.txt

यह दक्षता के लिए समझ में आता है, यदि आप किसी उपयोगकर्ता के साथ बातचीत कर रहे हैं, तो वे शायद हर पंक्ति को देखना चाहते हैं। यदि आप किसी फ़ाइल में आउटपुट भेज रहे हैं, तो यह सबसे अधिक संभावना है कि दूसरे छोर पर एक उपयोगकर्ता नहीं है (हालांकि असंभव नहीं है, वे फ़ाइल को सिलाई कर सकते हैं)। अब आप तर्क दे सकते हैं कि उपयोगकर्ता हर चरित्र को देखना चाहता है, लेकिन इसके साथ दो समस्याएं हैं।

पहला यह है कि यह बहुत कुशल नहीं है। दूसरा यह है कि मूल एएनएसआई सी जनादेश नए व्यवहार का आविष्कार करने के बजाय मुख्य रूप से मौजूदा व्यवहार को संहिताबद्ध करने के लिए था , और एएनएसआई प्रक्रिया शुरू होने से बहुत पहले उन डिजाइन निर्णयों को बनाया गया था। यहां तक ​​कि आईएसओ आजकल मानकों में मौजूदा नियमों को बदलते समय बहुत सावधानी से चलता है।

इससे कैसे निपटा जाए, यदि आप fflush (stdout)हर आउटपुट कॉल के बाद जिसे आप तुरंत देखना चाहते हैं, तो यह समस्या को हल कर देगा।

वैकल्पिक रूप से, आप इसे setvbufचालू करने से पहले उपयोग करने के लिए उपयोग कर सकते हैं stdout, इसे अनबाउंड में सेट करने के लिए और आपको fflushअपने कोड में उन सभी लाइनों को जोड़ने के बारे में चिंता करने की आवश्यकता नहीं होगी :

setvbuf (stdout, NULL, _IONBF, BUFSIZ);

बस ध्यान रखें कि यदि आप फ़ाइल में आउटपुट भेज रहे हैं तो प्रदर्शन को काफी प्रभावित कर सकता है । यह भी ध्यान रखें कि इसके लिए समर्थन कार्यान्वयन-परिभाषित है, मानक द्वारा गारंटी नहीं है।

आईएसओ C99 खंड 7.19.3/3प्रासंगिक सा है:

जब एक धारा अप्रभावित होती है , तो पात्रों को स्रोत से या गंतव्य पर जल्द से जल्द दिखाई देने का इरादा होता है। अन्यथा वर्णों को एक ब्लॉक के रूप में होस्ट वातावरण से संचित या प्रेषित किया जा सकता है।

जब एक स्ट्रीम पूरी तरह से बफ़र हो जाती है , तो वर्णों को एक बफर के रूप में होस्ट परिवेश से या एक ब्लॉक के रूप में प्रेषित किया जाता है।

जब एक स्ट्रीम को लाइन बफ़र किया जाता है , तो वर्णों को एक नए-पंक्ति वर्ण का सामना करने पर एक ब्लॉक के रूप में या मेजबान वातावरण से प्रेषित किया जाता है।

इसके अलावा, वर्णों को होस्ट वातावरण के लिए एक ब्लॉक के रूप में प्रेषित करने का इरादा है, जब एक बफर भर जाता है, जब इनपुट एक अप्रकाशित स्ट्रीम पर अनुरोध किया जाता है, या जब इनपुट एक लाइन बफ़र स्ट्रीम पर अनुरोध किया जाता है, जिसमें होस्ट वातावरण से वर्णों के प्रसारण की आवश्यकता होती है ।

इन विशेषताओं के लिए समर्थन कार्यान्वयन-परिभाषित है, setbufऔर setvbufकार्यों और कार्यों के माध्यम से प्रभावित हो सकता है।


8
मैं अभी एक ऐसे परिदृश्य में आया था जहाँ एक '\ n' है, प्रिंटफ () फ्लश नहीं करता है। जैसा कि आपने यहां बताया है, एक फफुंद (स्टडआउट) जोड़कर इसे दूर किया गया था। लेकिन मैं सोच रहा हूं कि क्यों '\ n' प्रिंटफ () में बफर को फ्लश करने में असफल रहा।
Qiang जू

11
@QiangXu, मानक आउटपुट केवल उस स्थिति में बफ़र किया जाता है, जहां यह एक इंटरैक्टिव डिवाइस को संदर्भित करने के लिए निश्चित रूप से निर्धारित किया जा सकता है। इसलिए, उदाहरण के लिए, यदि आप आउटपुट को पुनर्निर्देशित करते हैं myprog >/tmp/tmpfile, तो यह लाइन बफर के बजाय पूरी तरह से बफर है। मेमोरी से, यह निर्धारित करना कि क्या आपका मानक आउटपुट इंटरैक्टिव है, कार्यान्वयन के लिए छोड़ दिया गया है।
paxdiablo

3
इसके अलावा विंडोज कॉलिंग सेटवॉफ (...., _IOLBF) के रूप में काम नहीं करेगा _IOLBF _IOFBF के समान ही है: msdn.microsoft.com/en-us/library/86cebhhs.aspx
Piotr Lopusiewicz

28

यह शायद दक्षता की वजह से ऐसा है और क्योंकि अगर आपके पास एक ही TTY के लिए कई कार्यक्रम हैं, तो इस तरह से आपको एक पंक्ति में वर्ण नहीं मिलते हैं। इसलिए यदि प्रोग्राम A और B आउटपुट कर रहे हैं, तो आपको आमतौर पर मिलेगा:

program A output
program B output
program B output
program A output
program B output

यह बदबू आ रही है, लेकिन यह इससे बेहतर है

proprogrgraam m AB  ououtputputt
prproogrgram amB A  ououtputtput
program B output

ध्यान दें कि यह भी एक नई लाइन पर फ्लश करने की गारंटी नहीं है, इसलिए यदि आप फ्लश करते हैं तो आपको स्पष्ट रूप से फ्लश करना चाहिए।


26

तुरंत फ्लश कॉल करने के लिए fflush(stdout) या fflush(NULL)( NULLसब कुछ फ्लश करने का मतलब है)।


31
ध्यान रखें fflush(NULL);आमतौर पर एक बहुत बुरा विचार है। यह प्रदर्शन को मार देगा यदि आपके पास कई फाइलें खुली हैं, खासकर एक बहु-थ्रेडेड वातावरण में जहां आप ताले के लिए सब कुछ से लड़ेंगे।
आर .. गिटहब स्टॉप हेल्पिंग ICE

14

नोट: Microsoft रनटाइम लाइब्रेरीज़ लाइन बफ़रिंग का समर्थन नहीं करते हैं, इसलिए printf("will print immediately to terminal") :

https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setvbuf


3
से भी बदतर printf"सामान्य" मामले में टर्मिनल के लिए तुरंत जा रहा तथ्य यह है कि है printfऔर fprintfअधिक मोटे मामलों में जहां उनके उत्पादन तत्काल उपयोग के लिए रखा जाता है में भी बफ़र मिलता है। जब तक एमएस ने चीजों को तय नहीं किया है, जो एक प्रोग्राम को दूसरे से स्टैडर और स्टडआउट को कैप्चर करना असंभव बनाता है और यह पहचानता है कि प्रत्येक को किस क्रम में चीजें भेजी गई थीं।
सुपरकैट

नहीं, यह उस टर्मिनल पर तुरंत प्रिंट नहीं करता है जब तक कोई बफरिंग सेट नहीं किया गया था। डिफ़ॉल्ट रूप से पूर्ण बफरिंग प्रयोग किया जाता है
phuclv

12

स्टडआउट को बफ़र किया जाता है, इसलिए एक नई रूपरेखा के प्रिंट होने के बाद ही आउटपुट होगा।

तत्काल उत्पादन प्राप्त करने के लिए, या तो:

  1. Stderr पर प्रिंट करें।
  2. स्टडआउट को असंबद्ध बनाएं।

10
या fflush(stdout)
रस्ताजेडी

2
"तो केवल एक नई रूपरेखा मुद्रित होने के बाद ही आउटपुट होगा।" इतना ही नहीं कम से कम 4 अन्य मामलों में। करने के लिए पूर्ण, लिखने बफ़र stderr(इस जवाब बाद में उल्लेख है), fflush(stdout), fflush(NULL)
chux -

11

डिफ़ॉल्ट रूप से, stdout लाइन बफ़र्ड है, स्टैडर कोई भी बफ़र नहीं है और फ़ाइल पूरी तरह से बफ़र्ड है।


10

आप stderr को fprintf कर सकते हैं, जो इसके बजाय unbuffered है। या आप जब चाहें तब स्टडआउट को फ्लश कर सकते हैं। या आप अटूट को सेटआउट कर सकते हैं।


10

setbuf(stdout, NULL);बफ़रिंग को अक्षम करने के लिए उपयोग करें ।


2

आम तौर पर बफरिंग के 2 स्तर हैं-

1. कर्नेल बफर कैश (तेजी से पढ़ना / लिखना)

2. आई / ओ लाइब्रेरी में बफरिंग (सिस्टम कॉल की संख्या को कम करता है)

का उदाहरण लेते हैं fprintf and write()

जब आप कॉल करते हैं fprintf(), तो यह सीधे फाइल पर नहीं जाता है। यह सबसे पहले प्रोग्राम की मेमोरी में stdio बफर को जाता है। वहाँ से यह कर्नेल बफर कैश को राइट सिस्टम कॉल का उपयोग करके लिखा जाता है। तो I / O बफर को छोड़ने का एक तरीका सीधे लेखन () का उपयोग करना है। अन्य तरीके उपयोग कर रहे हैं setbuff(stream,NULL)। यह बफरिंग मोड को बिना बफरिंग के सेट करता है और डेटा सीधे कर्नेल बफर को लिखा जाता है। डेटा को कर्नेल बफर में स्थानांतरित करने के लिए, हम "\ n" का उपयोग कर सकते हैं, जो 'लाइन बफरिंग' के डिफ़ॉल्ट बफरिंग मोड के मामले में, I / O बफर को फ्लश करेगा। या हम उपयोग कर सकते हैं fflush(FILE *stream)

अब हम कर्नेल बफर में हैं। कर्नेल (/ OS) डिस्क एक्सेस समय को कम करना चाहता है और इसलिए यह डिस्क के केवल ब्लॉक को पढ़ता / लिखता है। इसलिए जब एक read()जारी किया जाता है, जो एक सिस्टम कॉल है और इसे सीधे या इसके माध्यम से लागू किया जा सकता हैfscanf() , तो कर्नेल डिस्क से डिस्क ब्लॉक पढ़ता है और इसे एक बफर में संग्रहीत करता है। इसके बाद डेटा को यहां से यूजर स्पेस में कॉपी किया जाता है।

इसी प्रकार fprintf()I / O बफर से प्राप्त डेटा को कर्नेल द्वारा डिस्क पर लिखा जाता है। इससे रीड () लिखना () तेज होता है।

अब कर्नेल को आरंभ करने के लिए बाध्य करने के लिए write(), जिसके बाद डेटा ट्रांसफर को हार्डवेयर नियंत्रकों द्वारा नियंत्रित किया जाता है, कुछ तरीके भी हैं। हम O_SYNCलेखन कॉल के दौरान झंडे या इसी तरह के झंडे का उपयोग कर सकते हैं । या हम fsync(),fdatasync(),sync()कर्नेल आरंभ करने के लिए अन्य कार्यों का उपयोग कर सकते हैं जैसे कि कर्नेल बफर में डेटा उपलब्ध है।

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