% P के साथ अशक्त बिंदुओं का मुद्रण अपरिभाषित व्यवहार है?


93

क्या %pरूपांतरण विनिर्देशक के साथ अशक्त बिंदुओं को प्रिंट करना अपरिभाषित व्यवहार है ?

#include <stdio.h>

int main(void) {
    void *p = NULL;

    printf("%p", p);

    return 0;
}

प्रश्न सी मानक पर लागू होता है, और सी कार्यान्वयन पर नहीं।


A वास्तव में यह नहीं सोचता कि कोई भी (C समिति सहित) इसके बारे में बहुत अधिक परवाह करता है। यह एक काफी कृत्रिम समस्या है, जिसका कोई (या लगभग नहीं) व्यावहारिक महत्व है।
P__J__

यह प्रिंटफ केवल मान को प्रदर्शित करता है, और स्पर्श नहीं करता है (इंगित ऑब्जेक्ट को पढ़ने या लिखने के अर्थ में) - यूबी नहीं हो सकता है I सूचक के पास इसके प्रकार के मूल्य के लिए मान्य है (NULL मान्य मूल्य है)
P__J__

3
@PeterJ चलो कहते हैं कि आप जो कह रहे हैं वह सच है (हालांकि स्पष्ट रूप से मानक राज्यों अन्यथा), अकेले तथ्य, कि हम इस पर बहस कर रहे हैं, यह सवाल को वैध और सही बनाता है, क्योंकि यह मानक के नीचे उद्धृत भाग जैसा दिखता है एक नियमित डेवलपर के लिए यह समझना बहुत कठिन है कि बिल्ली क्या चल रही है .. मतलब: सवाल नीचे वोट के लायक नहीं है, क्योंकि इस समस्या को स्पष्टीकरण की आवश्यकता है!
पीटर वेरो

1
संबंधित: stackoverflow.com/q/10461360/694576
alk

2
@PeterJ यह एक अलग कहानी है, तो स्पष्टीकरण के लिए धन्यवाद :)
पीटर वेरो

जवाबों:


93

यह उन अजीब कोने के मामलों में से एक है जहां हम अंग्रेजी भाषा की सीमाओं और मानक में असंगत संरचना के अधीन हैं। तो सबसे अच्छा, मैं एक सम्मोहक काउंटर-तर्क कर सकता हूं, क्योंकि यह साबित करना असंभव है :) 1


प्रश्न में कोड अच्छी तरह से परिभाषित व्यवहार प्रदर्शित करता है।

जैसा कि [let's.१.४] प्रश्न का आधार है, चलिए शुरू करते हैं:

निम्नलिखित विवरणों में से प्रत्येक तब तक लागू होता है जब तक कि स्पष्ट रूप से विस्तृत विवरणों में अन्यथा स्पष्ट रूप से कहा गया हो, जो अनुसरण नहीं करते हैं: यदि किसी फ़ंक्शन के तर्क में अमान्य मान है ( जैसे कि फ़ंक्शन के डोमेन के बाहर का मान, या प्रोग्राम के पता स्थान के बाहर एक संकेतक, या अशक्त सूचक , [... अन्य उदाहरण ...] ) [...] व्यवहार अपरिभाषित है। [... अन्य कथन ...]

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

इस प्रकार यह स्पष्ट है कि is.१.४ का इरादा / दायरा केवल इतना है कि एक "अमान्य मूल्य" यूबी की ओर जाता है ( जब तक कि अन्यथा नहीं कहा जाता है )। हमें प्रत्येक फ़ंक्शन के विवरण को यह देखने के लिए देखना होगा कि "अमान्य मान" के रूप में क्या मायने रखता है।

उदाहरण 1 - strcpy

[[.२१.२.३] केवल यही कहता है:

strcpyसमारोह प्रतियां स्ट्रिंग द्वारा की ओर इशारा किया s2(समाप्त अशक्त चरित्र सहित) सरणी में से की ओर इशारा किया s1। यदि ओवरलैप करने वाली वस्तुओं के बीच नकल होती है, तो व्यवहार अपरिभाषित है।

यह शून्य बिंदुओं का कोई स्पष्ट उल्लेख नहीं करता है, फिर भी यह शून्य टर्मिनलों का कोई उल्लेख नहीं करता है। इसके बजाय, "स्ट्रिंग द्वारा इंगित किया गया s2" से एक infers कि केवल मान्य मान स्ट्रिंग हैं (यानी वर्ण-निरपेक्ष वर्ण सरणियों को इंगित करता है )।

वास्तव में, इस पैटर्न को पूरे व्यक्तिगत विवरण में देखा जा सकता है। कुछ अन्य उदाहरण:

  • [[.६.४.१ (fenv)] द्वारा इंगित की गई वस्तु में वर्तमान फ्लोटिंग-पॉइंट पर्यावरण को संग्रहीत करेंenvp

  • [7.12.6.4 (frexp)] पूर्णांक में पूर्णांक की दुकान की ओर इशारा किया वस्तु सेexp

  • [7.19.5.1 (fclose)] धारा की ओर इशारा द्वाराstream

उदाहरण 2 - printf

[[.१ ९ .६.१] इसके बारे में कहते हैं %p:

p- तर्क एक सूचक होगा void। सूचक का मान कार्यान्वयन-परिभाषित तरीके से, मुद्रण वर्णों के अनुक्रम में परिवर्तित हो जाता है।

नल एक मान्य पॉइंटर मान है, और यह खंड कोई स्पष्ट उल्लेख नहीं करता है कि नल एक विशेष मामला है, और न ही सूचक को किसी ऑब्जेक्ट पर इंगित करना है। इस प्रकार यह परिभाषित व्यवहार है।


1. जब तक एक मानक लेखक आगे नहीं आता है, या जब तक कि हम चीजों को स्पष्ट करने वाले औचित्य दस्तावेज के समान कुछ नहीं पा सकते हैं।


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
भार्गव राव

1
"अभी तक यह अशक्त टर्मिनेटरों का कोई उल्लेख नहीं करता है" उदाहरण 1 में कमजोर है - स्ट्रैची जैसा कि " स्ट्रिंग को कॉपी करता है" कहता है । स्ट्रिंग को स्पष्ट रूप से एक अशक्त चरित्र के रूप में परिभाषित किया गया है ।
chux -

1
@chux - यह कुछ हद तक मेरी बात है - किसी को यह अनुमान लगाने की आवश्यकता है कि संदर्भ से वैध / अमान्य क्या है, बल्कि मान लें कि 7.1.4 में सूची संपूर्ण है। (हालांकि, मेरे जवाब के इस हिस्से के अस्तित्व ने टिप्पणियों के संदर्भ में कुछ और समझदारी पैदा कर दी है जो तब से हटाए गए हैं, यह तर्क देते हुए कि स्ट्रैपी एक प्रतिगामी था।)
ओलिवर चार्ल्सवर्थ

1
मुद्दे की जड़ यह है कि पाठक किस तरह से व्याख्या करेगा । क्या इसका मतलब है कि संभव अवैध मूल्यों के कुछ उदाहरण हैं ? क्या इसका मतलब कुछ उदाहरण हैं जो हमेशा अमान्य मान हैं ? रिकॉर्ड के लिए, मैं पहली व्याख्या के साथ जाता हूं।
निंजाल

1
@ ननजालज - हाँ, सहमत। यह अनिवार्य रूप से मैं यहां अपने उत्तर में बताने की कोशिश कर रहा हूं, अर्थात "ये उस प्रकार के उदाहरण हैं जो अमान्य मान हो सकते हैं"। :)
ओलिवर चार्ल्सवर्थ

20

संक्षिप्त उत्तर

जी हां%pरूपांतरण निर्दिष्ट के साथ मुद्रण नल बिंदुओं का अपरिभाषित व्यवहार होता है। यह कहने के बाद, मैं किसी भी मौजूदा अनुरूप कार्यान्वयन से अनजान हूँ जो दुर्व्यवहार करेगा।

उत्तर सी मानकों (C89 / C99 / C11) में से किसी पर लागू होता है।


दीर्घ उत्तर

%pरूपांतरण विनिर्देशक शून्य करने के लिए प्रकार सूचक की एक बहस की उम्मीद है, प्रिंट करने योग्य पात्रों को सूचक के रूपांतरण कार्यान्वयन परिभाषित किया गया है। यह बताता है कि अशक्त सूचक अपेक्षित नहीं है।

मानक लाइब्रेरी फ़ंक्शंस का परिचय बताता है कि जब तक कि यह स्पष्ट रूप से अन्यथा नहीं कहा जाता है, तब तक (मानक लाइब्रेरी) फ़ंक्शन के लिए अशक्त संकेत अमान्य मान माने जाते हैं।

C99 / C11 §7.1.4 p1

[...] यदि किसी फ़ंक्शन के तर्क में एक अमान्य मान है (जैसे [...] एक अशक्त सूचक, [...] व्यवहार अपरिभाषित है।

मान्य मानक के रूप में अशक्त बिंदुओं की अपेक्षा करने वाले (मानक पुस्तकालय) कार्यों के उदाहरण:

  • fflush() "सभी स्ट्रीम" (जो लागू होता है) को फ्लशिंग के लिए एक अशक्त सूचक का उपयोग करता है।
  • freopen() स्ट्रीम के साथ "वर्तमान में संबद्ध" फ़ाइल को इंगित करने के लिए एक शून्य सूचक का उपयोग करता है।
  • snprintf() शून्य 'n' शून्य होने पर एक पॉइंटर पॉइंटर पास करने की अनुमति देता है।
  • realloc() एक नई वस्तु आवंटित करने के लिए एक शून्य सूचक का उपयोग करता है।
  • free() एक अशक्त सूचक पारित करने की अनुमति देता है।
  • strtok() बाद के कॉल के लिए एक शून्य सूचक का उपयोग करता है।

यदि हम मामले को लेते हैं snprintf(), तो यह समझ में आता है कि शून्य सूचक को पास करने की अनुमति तब होती है जब 'n' शून्य होता है, लेकिन यह अन्य (मानक पुस्तकालय) कार्यों के लिए ऐसा नहीं है जो समान शून्य 'n' की अनुमति देता है। उदाहरण के लिए: memcpy(), memmove(), strncpy(), memset(), memcmp()

यह न केवल मानक पुस्तकालय के परिचय में निर्दिष्ट है, बल्कि इन कार्यों के लिए एक बार फिर से प्रस्तुत है:

C99 §7.21.1 p2 / C11 §7.24.1 p2

जहाँ size_tn के रूप में घोषित एक तर्क किसी फ़ंक्शन के लिए सरणी की लंबाई निर्दिष्ट करता है, n उस फ़ंक्शन के लिए कॉल पर मान शून्य हो सकता है। जब तक स्पष्ट रूप से अन्यथा इस उप-धारा में किसी विशेष कार्य के विवरण में कहा गया हो, ऐसे कॉल पर सूचक तर्क अभी भी मान्य मानों के रूप में 7.1.4 में वर्णित होंगे।


क्या यह जानबूझकर है?

मुझे नहीं पता कि %pएक अशक्त सूचक के साथ यूबी वास्तव में जानबूझकर है, लेकिन चूंकि मानक स्पष्ट रूप से बताता है कि अशक्त मान को मानक पुस्तकालय कार्यों के तर्क के रूप में अमान्य मान माना जाता है, और फिर यह स्पष्ट रूप से उन मामलों को निर्दिष्ट करता है जहां एक अशक्त है सूचक एक वैध तर्क (snprintf, नि: शुल्क, आदि) है, और फिर इसे चला जाता है और एक बार फिर से आवश्यकता को दोहराता तर्क शून्य में भी मान्य होने के लिए 'एन' मामलों में ( memcpy, memmove, memset), तो मुझे लगता है कि यह मान लेना कि उचित है C मानक समिति ऐसी चीजों के अपरिभाषित होने से बहुत चिंतित नहीं है।


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
भार्गव राव

1
@JeroenMostert: इस तर्क का क्या इरादा है? 7.1.4 का दिया गया उद्धरण बल्कि स्पष्ट है, है ना? "जब तक स्पष्ट रूप से अन्यथा नहीं कहा जाता है" के बारे में बहस करने के लिए क्या है जब इसे अन्यथा नहीं कहा जा रहा है? इस तथ्य के बारे में बहस करने के लिए क्या है कि (असंबंधित) स्ट्रिंग फ़ंक्शन लाइब्रेरी में एक समान शब्दांकन है, इसलिए शब्दांकन को प्रतीत नहीं होता है? मुझे लगता है कि यह उत्तर (वास्तव में व्यवहार में उपयोगी नहीं है ) जितना सही हो सकता है।
डेमन

3
@ डामन: आपका पौराणिक हार्डवेयर मिथकीय नहीं है, ऐसे बहुत से वास्तुशिल्प हैं जहाँ मान्य पते का प्रतिनिधित्व नहीं करने वाले मानों को पता रजिस्टरों में लोड नहीं किया जा सकता है। हालांकि, उन तर्कों को एक सामान्य तंत्र के रूप में कार्य करने के लिए अशक्त बिंदुओं को पास करना आवश्यक है। ढेर पर एक लगाने से चीजों को उड़ा नहीं दिया जाएगा।
११:५५

1
@anatolyg: x86 प्रोसेसर पर, पतों के दो भाग होते हैं - एक खंड और एक ऑफसेट। 8086 में, एक सेगमेंट रजिस्टर को लोड करना किसी अन्य को लोड करने के समान है, लेकिन बाद की सभी मशीनों पर यह एक सेगमेंट डिस्क्रिप्टर प्राप्त करता है। अमान्य डिस्क्रिप्टर लोड करने से जाल पैदा होता है। 80386 और बाद के प्रोसेसर के लिए बहुत सारे कोड, हालांकि, केवल एक सेगमेंट का उपयोग करते हैं, और इस प्रकार सेगमेंट रजिस्टर को कभी भी लोड नहीं करते हैं
सुपरकैट

1
मुझे लगता है कि हर कोई इस बात से सहमत होगा कि अशक्त सूचक को प्रिंट %pकरना अपरिभाषित व्यवहार नहीं है
MM

-1

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

इस सवाल का कि क्या यूबी कुछ बोलता है और शायद ही कभी उपयोगी होता है। महत्व के वास्तविक प्रश्न हैं:

  1. क्या किसी को जो क्वालिटी कंपाइलर लिखने की कोशिश कर रहा है, उसे प्रेडिक्टेबल फैशन का व्यवहार करना चाहिए? वर्णित परिदृश्य के लिए उत्तर स्पष्ट रूप से हाँ है।

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

  3. कुछ मोटे कंपाइलर लेखक मानक की व्याख्या को बढ़ा सकते हैं ताकि कुछ अजीब करने का औचित्य साबित हो सके? मैं उम्मीद नहीं करूंगा, लेकिन इसे खारिज नहीं करूंगा।

  4. व्यवहार के बारे में संकलक स्क्वाक को सैनिटाइज करना चाहिए? यह उनके उपयोगकर्ताओं के व्यामोह स्तर पर निर्भर करेगा; एक संकलक संकलक शायद इस तरह के व्यवहार के बारे में स्क्वाकिंग करने के लिए डिफ़ॉल्ट नहीं होना चाहिए, लेकिन संभवत: ऐसा करने के लिए कॉन्फ़िगरेशन विकल्प प्रदान करता है जो कि "चतुर" / गूंगा संकलक के लिए पोर्ट किया जा सकता है जो अजीब व्यवहार करता है।

यदि मानक की एक उचित व्याख्या का अर्थ है कि एक व्यवहार परिभाषित किया गया है, लेकिन कुछ संकलक लेखक व्याख्या को अन्यथा करने के औचित्य को बढ़ाते हैं, तो क्या यह वास्तव में मायने रखता है कि मानक क्या कहता है?


1. प्रोग्रामर के लिए यह आधुनिक नहीं है कि वे आधुनिक / आक्रामक ऑप्टिमाइज़र द्वारा बनाई गई धारणाओं को खोजने के लिए बाधाओं के साथ हों जो वे "उचित" या "गुणवत्ता" मानते हैं। 2. जब विनिर्देश में अस्पष्टता की बात आती है, तो कार्यान्वयनकर्ताओं के लिए यह असामान्य नहीं है कि वे क्या स्वतंत्रता ग्रहण कर सकते हैं। 3. यह सी मानकों समिति के सदस्यों की बात आती है, यहां तक कि वे हमेशा क्या 'सही' व्याख्या है, अकेले यह क्या जाने के लिए के रूप में सहमत नहीं हूँ चाहिए हो। उपरोक्त को देखते हुए, हमें किसकी उचित व्याख्या करनी चाहिए?
Dr K.

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

1
@JeroenMostert: "क्या X अपरिभाषित व्यवहार का आह्वान करता है" का जवाब अक्सर इस सवाल पर निर्भर करता है कि इसका मतलब क्या है। यदि एक कार्यक्रम को अपरिभाषित व्यवहार के रूप में माना जाता है यदि मानक एक अनुरूप कार्यान्वयन के व्यवहार पर कोई आवश्यकता नहीं लगाएगा, तो लगभग सभी कार्यक्रम यूबी को लागू करते हैं। मानक के लेखक स्पष्ट रूप से कार्यान्वयन को मनमाने ढंग से व्यवहार करने की अनुमति देते हैं यदि कोई प्रोग्राम घोंसला फ़ंक्शन बहुत गहराई से कॉल करता है, तो जब तक कि कार्यान्वयन सही ढंग से कम से कम एक (संभवतः वंचित) स्रोत पाठ को संसाधित कर सकता है जो स्टैडर्ड में अनुवाद की सीमा का अभ्यास करता है।
Supercat

@supercat: बहुत दिलचस्प है, लेकिन printf("%p", (void*) 0)मानक के अनुसार अपरिभाषित व्यवहार है या नहीं? गहरी नेस्टेड फ़ंक्शन कॉल चीन में चाय की कीमत के समान ही प्रासंगिक हैं। और हाँ, यूबी वास्तविक दुनिया के कार्यक्रमों में बहुत आम है - इसका क्या?
जेरेन मोस्टर्ट

1
@JeroenMostert: चूंकि मानक यूबी होने के रूप में लगभग किसी भी कार्यक्रम के संबंध में एक obtuse कार्यान्वयन की अनुमति देगा, इसलिए क्या बात होनी चाहिए जो गैर-obtuse कार्यान्वयन का व्यवहार होगा। यदि आपने ध्यान नहीं दिया, तो मैंने यूबी के बारे में केवल एक कॉपी / पेस्ट नहीं लिखा, लेकिन प्रश्न %pके प्रत्येक संभावित अर्थ के बारे में सवाल का जवाब दिया ।
सुपरकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.