क्या Snprintf () हमेशा शून्य समाप्त हो रहा है?


84

क्या स्निप्रफ हमेशा गंतव्य बफर को समाप्त करता है?

दूसरे शब्दों में, क्या यह पर्याप्त है:

या क्या आपको ऐसा करना है, अगर किसी दिन बहुत अधिक है?

मुझे इस बात में दिलचस्पी है कि मानक क्या कहते हैं और कुछ लोकप्रिय परिवाद क्या कर सकते हैं जो मानक व्यवहार नहीं है।


क्या आपको दूसरे उदाहरण में सोमस्टार या डीएसटी को समाप्त करने का मतलब है?
हडसन

@chux, मार्टिन बा ने स्वीकार किए गए उत्तर में कवर किया। :)
प्रो। फॉकन

@ मुझे लगता है कि यह अच्छा था, आपकी टिप्पणी ने केवल यह स्पष्ट कर दिया कि यदि मैं i 0 लंबा हूं, तो कुछ भी नहीं लिखा गया है। साथी स्टैकओवरफ्लॉवर के साथ चैट करने के लिए एक संभावित बहाने के रूप में मैं हर टिप्पणी लेता हूं। :)
प्रो। फाल्कन

@Prof। फाल्कन सहमत हैं कि टिप्पणी ठीक और स्पष्ट थी, लेकिन यह उत्तर के साथ बेमानी था - बस मेरी समीक्षा में याद किया।
chux -

stackoverflow.com/a/8712996/193892 विजुअल स्टूडियो अब स्निपरफ ()
प्रो।

जवाबों:


73

जैसा कि अन्य उत्तर स्थापित करते हैं: यह होना चाहिए :

snprintf... परिणामों को वर्ण स्ट्रिंग बफ़र पर लिखता है। (...) को शून्य वर्ण से समाप्त किया जाएगा, जब तक कि buf_size शून्य न हो।

तो आपको बस इतना ध्यान रखना है कि आप इसे शून्य-आकार के बफर पास न करें, क्योंकि (जाहिर है) यह शून्य को "कहीं नहीं" लिख सकता है।


हालाँकि, सावधान रहें कि Microsoft की लाइब्रेरी में कोई फ़ंक्शन नहीं है,snprintf बल्कि इसके बजाय ऐतिहासिक रूप से केवल एक फ़ंक्शन होता है _snprintf(नोट लीड को रेखांकित करता है ) जो एक समाप्ति नल को जोड़ नहीं देता है । यहां डॉक्स (VS 2012, ~~ VS 2013):

http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx

प्रतिलाभ की मात्रा

मान लें कि स्वरूपित डेटा स्ट्रिंग की लंबाई हो सकती है (समाप्ति नलिका शामिल नहीं है)। लेन और काउंट _snprintf के लिए बाइट्स में हैं, _snwprintf के लिए विस्तृत वर्ण।

  • यदि लेन <गणना, तो लेन वर्ण बफर में संग्रहीत किए जाते हैं, एक अशक्त टर्मिनेटर जोड़ा जाता है, और लेन वापस आ जाता है।

  • यदि लेन = गिनती, तो लेन वर्ण बफर में संग्रहीत किए जाते हैं, कोई नल-टर्मिनेटर जोड़ा नहीं जाता है, और लेन वापस आ जाता है।

  • यदि लेन> गिनती, तो गिनती वर्ण बफर में संग्रहीत किए जाते हैं, कोई नल-टर्मिनेटर जोड़ा नहीं जाता है, और एक नकारात्मक मान लौटाया जाता है।

(...)

विजुअल स्टूडियो 2015 (VC14) ने स्पष्ट रूप से अनुरूप snprintfकार्य शुरू किया , लेकिन अग्रणी अंडरस्कोर और गैर- शून्य व्यवहार वाला विरासत अभी भी है:

यह snprintfफ़ंक्शन आउटपुट को ट्रंक करता है जब लेन एक से अधिक या बराबर होता है, एक शून्य-टर्मिनेटर पर रखकर buffer[count-1]। (...)

के अलावा अन्य सभी कार्यों के लिए snprintf, अगर len = count, len वर्ण बफर में संग्रहीत किए जाते हैं, तो कोई नल-टर्मिनेटर जोड़ा नहीं जाता है (...)


24
असलन के नाम पर Microsoft इंजीनियर क्या सोच रहे थे जब उन्होंने पेश किया _snprintfजो चुपचाप एक प्रमुख सुरक्षा सुविधा को हटाsnprintf देता है और स्ट्रिंग को शून्य-समाप्त नहीं करने की अनुमति देता है ?!
कॉलिन डी बेनेट

2
@ColinDBennett - यह अजीब और शक्तिशाली कष्टप्रद है और मुझे कोई सुराग नहीं है अगर किसी ने सोचा कि सभी :-)
मार्टिन बा

2
@MartinBa हाँ क्षमा करें, मैंने जो परीक्षण किया था template <size_t size> int _snprintf_s(char (&buffer)[size], size_t count, const char *format [, argument] ...);और मुझे यह भी उल्लेख करना चाहिए कि यह केवल / जीएस (सुरक्षा जांच) संकलित ध्वज के साथ होता है। वह फ़ंक्शन आकार, गणना और लंबाई जानता है।
14 अक्टूबर को sekmet64


2
@ सज्जोन यह एक मूर्खतापूर्ण मूर्खता है (और शायद पूरी तरह से मूल) विस्मयादिबोधक ( मुहावरों की बात )। शायद एक छोटी सी शपथ के रूप में ( en.wikipedia.org/wiki/Minced_oath )। एक और उदाहरण "ज़ीउस के नाम पर क्या हो सकता है ...?" ( forum.wordreference.com/threads/in-the-name-of-zeus.2132965 )
कॉलिन डी बेनेट

19

स्निपर्फ (3) मैनपेज के अनुसार।

फ़ंक्शंस snprintf()और vsnprintf()अधिकांश sizeबाइट्स पर (अनुगामी नल बाइट ('0') सहित) लिखें str

तो, हाँ, आकार> = 1 होने पर समाप्त करने की कोई आवश्यकता नहीं है।


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

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

10

सी मानक के अनुसार, जब तक कि बफर का आकार 0 नहीं है, vsnprintf()और snprintf()अशक्त इसके उत्पादन को समाप्त कर देता है।

snprintf()समारोह के बराबर होगी sprintf(), एन तर्क जिसमें कहा गया है बफर के आकार रों से जाना जाता के योग के साथ। यदि n शून्य है, तो कुछ भी नहीं लिखा जाएगा और s एक अशक्त सूचक हो सकता है। अन्यथा, n-1st से परे आउटपुट बाइट्स को सरणी में लिखे जाने के बजाय छोड़ दिया जाएगा, और नल बाइट वास्तव में सरणी में लिखे गए बाइट्स के अंत में लिखा गया है।

इसलिए, यदि आपको यह जानने की जरूरत है कि एक बफर को कितना बड़ा आवंटित करना है, तो शून्य के आकार का उपयोग करें, और फिर आप गंतव्य के रूप में एक शून्य सूचक का उपयोग कर सकते हैं। ध्यान दें कि मैं POSIX पृष्ठों से जुड़ा हुआ हूं, लेकिन ये स्पष्ट रूप से कहते हैं कि मानक C और POSIX के बीच कोई भी विचलन होने का इरादा नहीं है जहां वे एक ही जमीन को कवर करते हैं:

इस संदर्भ पृष्ठ पर वर्णित कार्यक्षमता आईएसओ सी मानक के साथ संरेखित है। यहां वर्णित आवश्यकताओं और आईएसओ सी मानक के बीच कोई भी संघर्ष अनजाने में है। POSIX.1-2008 का यह आयतन ISO C मानक को दर्शाता है।

Microsoft संस्करण से सावधान रहें vsnprintf()। यह निश्चित रूप से मानक सी संस्करण से अलग व्यवहार करता है जब बफर में पर्याप्त जगह नहीं होती है (यह -1 लौटता है जहां मानक फ़ंक्शन आवश्यक लंबाई लौटाता है)। यह पूरी तरह से स्पष्ट नहीं है कि Microsoft संस्करण नल अपने उत्पादन को त्रुटि स्थितियों में समाप्त करता है, जबकि मानक C संस्करण करता है।

नोट क्या आप TR 24731 सुरक्षित कार्यों का उपयोग करते हैं? ( Microsoft संस्करण के लिए MSDN देखें vsprintf_s()) और सुरक्षित विकल्प के लिए मैक समाधान सी मानक पुस्तकालय कार्यों को असुरक्षित करने के लिए?


अरे, दुष्ट, ऐसा कभी नहीं सोचा था। दूसरी ओर ... :)
प्रो। फॉकन

आह, मुझे लगता है कि MS vsprintf () बिट मुझे, और मैंने उठाया कि - 1 आदत
प्रो। फॉकन

4

SunOS के कुछ पुराने संस्करणों ने स्निपरफ के साथ अजीब चीजें कीं और हो सकता है कि आउटपुट को NUL-समाप्त न किया हो और उन रिटर्न मानों का मिलान न किया हो जो बाकी सभी कर रहे थे, लेकिन पिछले 10 वर्षों में जो कुछ भी जारी किया गया है वह C99 क्या कर रहा है कहते हैं।


मुझे लगता है कि XP ​​10 साल से थोड़ा पहले जारी किया गया था। :-)
प्रो। फॉकन

और इस साल इसका पालन किया गया था। :)
प्रो। फालकेन

4

अस्पष्टता सी स्टैंडर्ड से ही शुरू होती है। C99 और C11 दोनों में snprintfफ़ंक्शन का समान विवरण है । यहाँ C99 से विवरण है:

7.19.6.5 snprintfसमारोह
सार
1 #include <stdio.h> int snprintf(char * restrict s, size_t n, const char * restrict format, ...);
विवरण
2 snprintfसमारोह के बराबर है fprintf, सिवाय इसके कि उत्पादन एक सरणी (तर्क द्वारा निर्दिष्ट में लिखा है s) के बजाय एक धारा की तुलना में। यदि nशून्य है, तो कुछ भी नहीं लिखा है, और sएक शून्य सूचक हो सकता है। अन्यथा, n-1सरणी से परे आउटपुट वर्ण को सरणी में लिखे जाने के बजाय छोड़ दिया जाता है, और एक अशक्त चरित्र वास्तव में सरणी में लिखे गए वर्णों के अंत में लिखा जाता है। यदि ओवरलैप करने वाली वस्तुओं के बीच नकल होती है, तो व्यवहार अपरिभाषित है।
रिटर्न
3 snprintfफ़ंक्शन फ़ंक्शन को लिखे गए वर्णों की संख्या देता हैnपर्याप्त रूप से बड़ा हो गया है, यदि एन्कोडिंग त्रुटि हुई है, तो समाप्त करने वाले अशक्त चरित्र या एक नकारात्मक मूल्य की गिनती नहीं। इस प्रकार, शून्य-समाप्त आउटपुट पूरी तरह से लिखा गया है अगर और केवल अगर लौटाया गया मूल्य nonnegative और से कम है n

एक ओर सजा

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

का कहना है कि
अगर ( s3-वर्ण-लंबी सरणी के nबिंदु , और) 3 है, तो 2 वर्ण लिखे जाएंगे, और 2 वें से परे के वर्णों को छोड़ दिया गया है ; फिर शून्य वर्ण उन 2 के बाद लिखा जाता है (और अशक्त वर्ण 3 वर्ण लिखा जाएगा)

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

दूसरी ओर
अंतिम वाक्य

इस प्रकार, शून्य-समाप्त आउटपुट पूरी तरह से लिखा गया है अगर और केवल अगर लौटाया गया मूल्य nonnegative और से कम है n

अस्पष्टता देता है (या मेरी अंग्रेजी अच्छी नहीं है)। मैं इस वाक्य को कम से कम दो तरीकों से व्याख्या कर सकता हूं:
1. आउटपुट शून्य-समाप्त हो गया है यदि और केवल यदि लौटाया गया मूल्य nonnegative है और उससे कम हैn (जिसका अर्थ है कि यदि लौटाया गया मान से कम नहीं है n, अर्थात आउटपुट (सहित) शून्य चरित्र समाप्त करना) सरणी में फिट नहीं होता है, तो आउटपुट शून्य-समाप्त नहीं होता है )।
2. आउटपुट पूरा हो गया है (कोई वर्ण नहीं छोड़ा गया है) यदि और केवल यदि लौटाया गया मूल्य nonnegative और से कम हैn


मेरा मानना ​​है कि व्याख्या 1 से ऊपर ANSWER विरोधाभास, गलतफहमी और लंबी चर्चा का कारण बनता है। इसीलिए snprintfफ़ंक्शन का वर्णन करने वाले अंतिम वाक्य को किसी भी अस्पष्टता को दूर करने के लिए बदलाव की आवश्यकता होती है (जो कि सी भाषा मानक को प्रस्ताव लिखने के लिए आधार देता है)।
मेरा मानना ​​है कि गैर-अस्पष्ट शब्दों का उदाहरण http://en.cppreference.com/w/c/io/fprintf (देखें 4)) से लिया जा सकता है , इस लिंक के लिए @ "मार्टिन बा" का धन्यवाद।

यह भी देखें कि प्रश्न " स्नप्रिंट: क्या इस फंक के विवरण को बदलने के लिए कोई सी मानक प्रस्ताव / योजनाएं हैं? "


4
आपकी व्याख्या 1 मुझे बिल्कुल नहीं लगती। मैं उस वाक्य को "आउटपुट के रूप में (जो संयोगवश, अशक्त है) के रूप में पूरी तरह से लिखा गया है अगर ..." जिसे मैं केवल # 2 के रूप में समझ सकता हूं।
zwol

1
वाक्य का नकार "शून्य-समाप्त आउटपुट पूरी तरह से लिखा गया है" है "शून्य-समाप्त आउटपुट पूरी तरह से लिखा नहीं गया है"। और कुछ नहीं। अपने आप में नकारात्मक वाक्य का अर्थ यह नहीं है कि कुछ भी लिखा गया है (इसमें अधूरा अशक्त-समाप्त आउटपुट, अपूर्ण गैर-शून्य-समाप्त आउटपुट या बेरंग हरे विचार शामिल हैं)। मानक में कोई अन्य स्थान कहता है कि जब आउटपुट अधूरा होता है तो वास्तव में क्या लिखा जाता है, और उस स्थान पर कहा गया है कि जब तक यह खाली नहीं होता है तब तक उत्पादन को समाप्त कर दिया जाता है (n == 0)।
एन। 'सर्वनाम' मी।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.