क्यों प्रिंट के साथ अग्रणी के बजाय अनुगामी newlines का उपयोग करें?


79

मैंने सुना है कि आपको उपयोग करते समय अग्रणी नईलाइन्स से बचना चाहिए printf। ताकि printf("\nHello World!")आप के बजाय का उपयोग करना चाहिएprintf("Hello World!\n")

ऊपर इस विशेष उदाहरण में इसका कोई मतलब नहीं है, क्योंकि आउटपुट अलग होगा, लेकिन इस पर विचार करें:

printf("Initializing");
init();
printf("\nProcessing");
process_data();
printf("\nExiting");

की तुलना में:

printf("Initializing\n");
init();
printf("Processing\n");
process_data();
printf("Exiting");

मैं नई रूपरेखाओं के साथ कोई लाभ नहीं देख सकता, सिवाय इसके कि यह बेहतर दिखती है। क्या कोई और कारण है?

संपादित करें:

मैं अब और यहाँ करीबी वोटों को संबोधित करूँगा। मुझे नहीं लगता कि यह स्टैक ओवरफ्लो से संबंधित है, क्योंकि यह प्रश्न मुख्य रूप से डिजाइन के बारे में है। मैं यह भी कहूंगा कि हालांकि यह इस मामले पर राय हो सकती है, किलियन फोथ का जवाब और सेमीस्टर का जवाब यह साबित करता है कि वास्तव में एक दृष्टिकोण के साथ बहुत उद्देश्य लाभ हैं।


5
यह प्रश्न "कोड वाले मुद्दों" (जो कि ऑफ-टॉपिक है) और "वैचारिक सॉफ़्टवेयर डिज़ाइन" (जो ऑन-टॉपिक है) के बीच सीमा पर है। यह बंद हो सकता है, लेकिन इसे बहुत मुश्किल मत लो। मुझे लगता है कि ठोस कोड उदाहरण जोड़ना सही विकल्प था।
सिल्वेन फोथ

46
अंतिम पंक्ति एक अनुगामी न्यूलाइन के बिना लिनक्स पर कमांड प्रॉम्प्ट के साथ विलय करेगी।
ग्रैंडमास्टरबी

4
यदि यह "बेहतर दिखता है" और इसका कोई नकारात्मक पहलू नहीं है, तो यह करने के लिए एक अच्छा पर्याप्त कारण है, आईएमओ। अच्छा कोड लिखना एक अच्छा उपन्यास या एक अच्छा तकनीकी पेपर लिखने के लिए अलग नहीं है - शैतान हमेशा विस्तार में होता है।
एलेफज़रो

5
खुद कुछ भी करो init()और process_data()छापो? यदि आप ऐसा करते हैं तो आप परिणाम की अपेक्षा क्या करेंगे?
बेर्गी

9
\nएक लाइन टर्मिनेटर है , एक लाइन विभाजक नहीं है । यह इस तथ्य से स्पष्ट होता है कि पाठ फ़ाइलें, यूनिक्स पर, लगभग हमेशा समाप्त होती हैं \n
जोनाथन रेनहार्ट

जवाबों:


222

टर्मिनल I / O की एक उचित राशि लाइन-बफ़र्ड है , इसलिए \ n के साथ एक संदेश समाप्त करने से आप निश्चित हो सकते हैं कि यह समयबद्ध तरीके से प्रदर्शित होगा। एक प्रमुख \ n संदेश के साथ या एक बार में प्रदर्शित नहीं किया जा सकता है। अक्सर, इसका मतलब यह होगा कि प्रत्येक चरण पिछले चरण के प्रगति संदेश को प्रदर्शित करता है , जिससे किसी कार्यक्रम के व्यवहार को समझने की कोशिश करने पर भ्रम और व्यर्थ समय का कोई अंत नहीं होता है।


20
किसी प्रोग्राम को क्रैश करने के लिए प्रिंटफ़ का उपयोग करते समय यह विशेष रूप से महत्वपूर्ण है। प्रिन्ट के अंत में न्यूलाइन डालने का अर्थ है कि कंसोल पर आने वाला स्टडआउट प्रत्येक प्रिन्ट पर फ्लश हो जाता है। (ध्यान दें कि जब stdout को किसी फ़ाइल में रीडायरेक्ट किया जाता है, तो std लाइब्रेरी आमतौर पर लाइन बफरिंग के बजाय ब्लॉक बफरिंग करते हैं, जिससे
प्रिंटफ

25
@ErikEidt ध्यान दें कि आपको fprintf(STDERR, …)इसके बजाय उपयोग करना चाहिए , जो आम तौर पर नैदानिक ​​आउटपुट के लिए बिल्कुल भी बफर नहीं होता है।
डेडुप्लिकेटर

4
@Deduplicator त्रुटि संदेशों में डायग्नोस्टिक संदेश लिखने के साथ-साथ इसके डाउनसाइड भी होते हैं - कई स्क्रिप्ट मान लेते हैं कि कोई प्रोग्राम फेल हो गया है तो कुछ त्रुटि स्ट्रीम में लिखा है।
वू

54
@Voo: मेरा तर्क है कि स्टडर को लिखने वाला कोई भी प्रोग्राम इंगित करता है कि विफलता स्वयं गलत है। प्रक्रिया का निकास कोड वह है जो इंगित करता है कि यह विफल हुआ या नहीं। यदि यह एक विफलता थी, तो stderr आउटपुट क्यों समझाएगा । यदि प्रक्रिया सफलतापूर्वक समाप्त हो जाती है (कोड शून्य से बाहर) तो stderr आउटपुट को मानव उपयोगकर्ता के लिए सूचनात्मक उत्पादन माना जाना चाहिए, जिसमें कोई विशेष मशीन-पार्स करने योग्य शब्दार्थ नहीं होता है (इसमें मानव-पठनीय चेतावनी हो सकती है, उदाहरण के लिए), जबकि stdout वास्तविक आउटपुट है कार्यक्रम, संभवतः आगे की प्रक्रिया के लिए उपयुक्त है।
डैनियल प्रीडेन

23
@Voo: आप किन कार्यक्रमों का वर्णन कर रहे हैं? मैं किसी भी व्यापक रूप से उपयोग किए जाने वाले सॉफ़्टवेयर पैकेज के बारे में नहीं जानता, जो आपके द्वारा वर्णित व्यवहार करता है। मुझे पता है कि ऐसे कार्यक्रम हैं जो करते हैं, लेकिन ऐसा नहीं है कि मैंने अभी ऊपर दिए गए अधिवेशन का वर्णन किया है: यह एक यूनिक्स या यूनिक्स जैसे पर्यावरण के काम में अधिकांश कार्यक्रम और मेरे ज्ञान का तरीका है, जिस तरह से अधिकांश कार्यक्रम हमेशा होते हैं। मैं निश्चित रूप से किसी भी कार्यक्रम के लिए वकालत लिखने से बचने की वकालत नहीं करूंगा क्योंकि कुछ स्क्रिप्ट इसे अच्छी तरह से नहीं संभालती हैं।
डैनियल प्रेडेन

73

POSIX सिस्टम (मूल रूप से कोई भी linux, BSD, जो भी ओपन-सोर्स बेस्ड सिस्टम आपको मिल सकता है) पर, एक लाइन को अक्षरों की एक स्ट्रिंग के रूप में परिभाषित किया जाता है जिसे एक नई लाइन द्वारा समाप्त किया जाता है \n। यह बुनियादी धारणा सभी मानक कमांड लाइन उपकरण पर, (लेकिन सीमित नहीं) सहित का निर्माण होता है wc, grep, sed, awk, और vim। यही कारण है कि कुछ संपादक (जैसे vim) हमेशा \nएक फ़ाइल के अंत में जोड़ते हैं , और सी के पहले मानकों को एक \nचरित्र के साथ समाप्त करने की आवश्यकता क्यों होती है ।

Btw: \nसमाप्त लाइनें होने से पाठ का प्रसंस्करण बहुत आसान हो जाता है: आप यह सुनिश्चित करने के लिए जानते हैं कि जब आपको वह टर्मिनेटर मिल गया है तो आपको पूरी लाइन मिल गई है। और आप यह सुनिश्चित करने के लिए जानते हैं कि यदि आपको अभी तक उस टर्मिनेटर का सामना नहीं करना है, तो आपको और अधिक पात्रों को देखने की आवश्यकता है।

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


25
यह सॉफ्टवेयर इंजीनियरिंग में सबसे पुरानी बहसों में से एक है: क्या लाइन टर्मिनेटर या लाइन सेपरेटर के रूप में न्यूलाइन्स (या, प्रोग्रामिंग भाषा में, स्टेटमेंट का एक और अंत "अर्धविराम की तरह) का उपयोग करना बेहतर है ? दोनों दृष्टिकोणों के अपने पक्ष और विपक्ष हैं। विंडोज दुनिया ज्यादातर इस विचार पर बैठ गई है कि न्यूलाइन अनुक्रम (जो कि आमतौर पर सीआर एलएफ है) एक लाइन विभाजक है , और इस प्रकार एक फ़ाइल में अंतिम पंक्ति को इसके साथ समाप्त होने की आवश्यकता नहीं है। यूनिक्स दुनिया में, हालांकि, एक नयालाइन अनुक्रम (एलएफ) एक लाइन टर्मिनेटर है , और इस धारणा के आसपास कई कार्यक्रम बनाए जाते हैं।
डैनियल प्राइडेन

33
POSIX यहां तक ​​कि एक पंक्ति को "शून्य या अधिक गैर-न्यूलाइन वर्णों के एक अनुक्रम और एक समाप्ति न्यूलाइन वर्ण के रूप में परिभाषित करता है ।"
पाइप

6
यह देखते हुए कि @ पिप कहते हैं, यह POSIX विनिर्देशन में है, हम शायद इसे de jure कह सकते हैं क्योंकि यह वास्तव में उत्तर बताता है?
बाल्ड्रिक

4
@ बाल्ड्रिक राइट। मैंने अपने उत्तर को और अधिक सकारात्मक होने के लिए अद्यतन किया है।
cmaster

सी भी स्रोत फ़ाइलों के लिए यह सम्मेलन करता है: एक गैर-खाली स्रोत फ़ाइल जो एक नई पंक्ति के साथ समाप्त नहीं होती है, अपरिभाषित व्यवहार पैदा करती है।
आर ..

31

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

यदि आप अग्रणी-न्यूलाइन लाइनों को स्टैंडर्ड ट्रेलिंग-न्यूलाइन लाइनों के साथ इंटरलेय करते हैं, तो "यह इस तरह दिखाई देगा:

Trailing-newline-line
Trailing-newline-line

Leading-newline-line
Leading-newline-line
Leading-newline-lineTrailing-newline-line
Trailing-newline-line

Leading-newline-lineTrailing-newline-line
Trailing-newline-line
Trailing-newline-line

... जो संभवत: वह नहीं है जो आप चाहते हैं।

यदि आप अपने कोड में केवल प्रमुख समाचारों का उपयोग करते हैं और केवल इसे IDE में चलाते हैं, तो यह ठीक हो सकता है। जैसे ही आप इसे किसी टर्मिनल में चलाते हैं या अन्य लोगों का कोड पेश करते हैं जो आपके कोड के साथ STDOUT को लिखेंगे, आपको ऊपर जैसा अवांछनीय आउटपुट दिखाई देगा।


2
कुछ ऐसा ही उन कार्यक्रमों के साथ होता है जो एक इंटरैक्टिव शेल में बाधित होते हैं - यदि एक आंशिक रेखा मुद्रित होती है (इसकी नई रेखा याद आती है), तो शेल भ्रमित हो जाता है कि किस स्तंभ पर कर्सर है, जिससे अगली कमांड लाइन को संपादित करना मुश्किल हो जाता है। जब तक आप अपने लिए एक अग्रणी नई पंक्ति नहीं जोड़ते हैं $PS1, जो तब पारंपरिक कार्यक्रमों के बाद एक अड़चन होगी।
टॉबी स्पाइट

17

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

मेरी राय में, अनुवर्ती कार्यक्रम को अधिक पठनीय बनाते हैं:

  1. एक उच्च सिग्नल-टू-शोर अनुपात (उर्फ सरल लेकिन सरल नहीं)
  2. महत्वपूर्ण विचार पहले आते हैं

उपरोक्त बिंदुओं से, हम यह तर्क दे सकते हैं कि नई अनुगामी बेहतर हैं। संदेश की तुलना में न्यूलाइन्स "शोर" को स्वरूपित कर रहे हैं, संदेश को बाहर खड़ा होना चाहिए और इस तरह पहले आना चाहिए (सिंटैक्स-हाइलाइटिंग भी मदद कर सकता है)।


19
हाँ, "ok\n"की तुलना में बहुत बेहतर है "\nok"...
cmaster

@cmaster: मुझे C में Pascal-string APIs का उपयोग करके MacOS के बारे में पढ़ने की याद दिलाता है, जिसमें मैजिक एस्केप कोड जैसे सभी स्ट्रिंग लिटरल्स को प्रीफ़िक्स करना आवश्यक है "\pFoobar"
ग्रैविटी

16

अनुगामी newlines का उपयोग बाद के संशोधनों को सरल करता है।

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

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

अब विचार करें कि कैसे इस तथ्य को संभालने के लिए जा रहे हैं कि आपका नया आउटपुट वास्तव में वैकल्पिक है, इसलिए "\ nInitializing" में आपका परिवर्तन कभी-कभी आउटपुट की शुरुआत में एक अवांछित रिक्त रेखा पैदा करता है ...

क्या आप एक वैश्विक ( झटका हॉरर ?? !!! ) सेट करते हैं, यह कहते हुए कि क्या कोई पूर्ववर्ती आउटपुट था और इसे "प्रारंभिक" को वैकल्पिक अग्रणी "\ n" के साथ मुद्रित करने के लिए परीक्षण करें, या क्या आप "\ n" के साथ आउटपुट करते हैं अपने पहले के आउटपुट और भविष्य के कोड पाठकों को यह सोच कर छोड़ दें कि इस "प्रारंभिक" में अन्य सभी आउटपुट संदेशों की तरह अग्रणी "\ n" क्यों नहीं है?

यदि आप लगातार नई अनुगामी का उत्पादन करते हैं, तो उस बिंदु पर जहां आप जानते हैं कि आप उस पंक्ति के अंत तक पहुँच चुके हैं जिसे समाप्त करने की आवश्यकता है, आप उन सभी मुद्दों को दरकिनार कर देते हैं। ध्यान दें, कि कुछ तर्क के अंत में एक अलग-अलग पुट ("\ n") स्टेटमेंट की आवश्यकता हो सकती है, जो एक लाइन पीस को आउटपुट करता है, लेकिन आप जिस कोड को जानते हैं, आपको उस स्थान पर सबसे नई जगह पर आउटपुट देना होगा। यह करो, कहीं और नहीं।


1
यदि प्रत्येक स्वतंत्र आउटपुट आइटम को अपनी लाइन पर दिखाई देना चाहिए, तो नई लाइनों का अनुगमन ठीक काम कर सकता है। यदि व्यावहारिक होने पर कई वस्तुओं को समेकित किया जाना चाहिए, हालांकि, चीजें अधिक जटिल हो जाती हैं। यदि यह एक सामान्य दिनचर्या के माध्यम से सभी आउटपुट को खिलाने के लिए व्यावहारिक है, तो अंतिम वर्ण एक सीआर था, तो एक स्पष्ट-टू-एंड-ऑफ-लाइन सम्मिलित करने के लिए एक ऑपरेशन, अगर अंतिम चरित्र एक नई पंक्ति और कुछ नया नहीं था, अगर अंतिम चरित्र अगर प्रोग्राम को स्वतंत्र लाइनों के अनुक्रम के अलावा कुछ और करने की आवश्यकता हो तो कुछ और मददगार हो सकता है।
सुपरकाट

7

क्यों प्रिंट के साथ अग्रणी के बजाय अनुगामी newlines का उपयोग करें?

बारीकी से सी कल्पना मैच।

सी लाइब्रेरी एक लाइन को एक नए-लाइन वर्ण के साथ समाप्त होने के रूप में परिभाषित करता है । '\n'

एक पाठ धारा में बना पात्रों में से एक का आदेश दिया अनुक्रम है लाइनों , शून्य या अधिक वर्ण से मिलकर प्रत्येक पंक्ति के साथ साथ एक समाप्त नई लाइन चरित्र। क्या अंतिम पंक्ति के लिए एक नई नई पंक्ति वर्ण की आवश्यकता होती है जो कार्यान्वयन-परिभाषित है। C11 §7.21.2 2

कोड जो लाइनों के रूप में डेटा लिखता है, फिर लाइब्रेरी की उस अवधारणा से मेल खाएगा।

printf("Initializing"); // Write part of a line
printf("\nProcessing"); // Finish prior line & write part of a line
printf("\nExiting");    // Finish prior line & write an implementation-defined last line

printf("Initializing\n");//Write a line 
printf("Processing\n");  //Write a line
printf("Exiting");       //Write an implementation-defined last line

पुन: अंतिम पंक्ति के लिए एक नई पंक्ति वर्ण को समाप्त करने की आवश्यकता होती है । मैं हमेशा '\n'आउटपुट पर एक अंतिम लिखने और इनपुट पर इसकी अनुपस्थिति को सहन करने की सलाह दूंगा।


वर्तनी जांच

मेरी वर्तनी जाँचकर्ता शिकायत करता है। शायद आपका भी।

  v---------v Not a valid word
"\nProcessing"

 v--------v OK
"Processing\n");

मैंने एक बार ispell.elउस से बेहतर सामना करने के लिए सुधार किया था । मैं मानता हूं कि यह अधिक बार \tसमस्या थी, और इसे केवल कई टोकन में स्ट्रिंग को तोड़कर टाला जा सकता था, लेकिन यह HTML के गैर-पाठ भागों को चुनिंदा रूप से छोड़ने के लिए और अधिक सामान्य "उपेक्षा" कार्य का एक साइड-इफेक्ट था। या MIME निकायों को मल्टीपार्ट करें, और कोड के गैर-टिप्पणी वाले हिस्से। मेरा हमेशा से मतलब था कि इसे उन भाषाओं में बदल दिया जाए जहाँ उपयुक्त मेटाडेटा (जैसे <p lang="de_AT">या Content-Language: gd) है, लेकिन कभी गोल टिट नहीं मिली। और अनुचर ने मेरे पैच को एक सिरे से खारिज कर दिया। :-(
टोबी स्पाइट

@TobySpeight यहां एक गोल टिट है । अपने पुन: सुधार की कोशिश करने के लिए तत्पर हैं ispell.el
चक्स

4

नई नई शर्तों के कारण अक्सर कोड लिखना आसान हो जाता है, उदाहरण के लिए,

printf("Initializing");
if (jobName != null)
    printf(": %s", jobName);
init();
printf("\nProcessing");

(लेकिन जैसा कि कहीं और नोट किया गया है कि आपको सीपीयू समय लेने वाले किसी भी कदम को करने से पहले आउटपुट बफर को फ्लश करने की आवश्यकता हो सकती है।)

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


1
क्या आप बता सकते हैं कि नई संस्करण की अनुगामी के साथ इस संस्करण को लिखना आसान क्यों है? इस उदाहरण में यह मेरे लिए स्पष्ट नहीं है। इसके बजाय मैं अगले आउटपुट के साथ आने वाली समस्याओं को उसी पंक्ति में जोड़कर देख सकता था "\nProcessing"
रायमुंड क्रमर

रायमुंड की तरह, मैं भी इस तरह से काम करने से उत्पन्न होने वाली समस्याओं को देख सकता हूं। आपको कॉल करते समय आसपास के प्रिंट पर विचार करने की आवश्यकता है printf। क्या होगा यदि आप पूरी "प्रारंभिक" लाइन को सशर्त बनाना चाहते थे? आपको यह जानने के लिए कि क्या आपको किसी नई पंक्ति के साथ उपसर्ग करना चाहिए या नहीं, उस स्थिति में "कार्यवाही" पंक्ति को शामिल करना होगा। यदि आगे एक और प्रिंट है और आपको "प्रसंस्करण" लाइन को सशर्त करने की आवश्यकता है, तो आपको यह जानने के लिए कि क्या आपको एक और नई लाइन के साथ उपसर्ग करना चाहिए, और प्रत्येक प्रिंट के लिए आगे की स्थिति में अगले प्रिंट को शामिल करना होगा।
जोएल

2
मैं सिद्धांत से सहमत हूं, लेकिन उदाहरण एक अच्छा नहीं है। एक अधिक प्रासंगिक उदाहरण कोड के साथ होगा जो कि प्रति पंक्ति कुछ वस्तुओं का उत्पादन करने वाला होता है। यदि आउटपुट को हेडर के साथ शुरू करना है जो एक नई लाइन के साथ समाप्त होता है, और प्रत्येक पंक्ति को हेडर से शुरू करना है, तो यह कहना आसान हो सकता है, उदाहरण के लिए if ((addr & 0x0F)==0) printf("\n%08X:", addr);और बिना शर्त के आउटपुट पर एक नई लाइन जोड़ना प्रत्येक पंक्ति के हेडर और अनुगामी न्यूलाइन के लिए अलग कोड।
सुपरकैट

1

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

यदि आप एक पूर्व लिखित लाइन (या तो एक स्थिर, या पहले से ही स्वरूपित - जैसे के साथ sprintf()) मुद्रित करना चाहते हैं , तो puts()प्राकृतिक (और कुशल) विकल्प है। हालांकि, puts()पिछली पंक्ति को समाप्त करने और एक अनर्जित लाइन लिखने का कोई तरीका नहीं है - यह हमेशा लाइन टर्मिनेटर लिखता है।

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