(क्यों) एक असमान परिवर्तनशील अपरिभाषित व्यवहार का उपयोग कर रहा है?


82

अगर मेरे पास:

यह स्पष्ट है कि इस अभिव्यक्ति के बाद शून्य x होना चाहिए, लेकिन हर जगह मैं देखता हूं, वे कहते हैं कि इस कोड का व्यवहार अपरिभाषित है, न कि केवल मूल्य x(घटाव से पहले तक)।

दो सवाल:

  • क्या इस कोड का व्यवहार वास्तव में अपरिभाषित है?
    (उदाहरण एक आज्ञाकारी प्रणाली पर कोड दुर्घटना [या बदतर] हो सकता है?]

  • यदि हां, तो C यह क्यों कहता है कि व्यवहार अपरिभाषित है, जब यह पूरी तरह स्पष्ट है कि xयहां शून्य होना चाहिए?

    अर्थात यहाँ व्यवहार को परिभाषित न करने से क्या लाभ है?

स्पष्ट रूप से, कंपाइलर बस चर के अंदर "काम" के रूप में जो भी कचरा मूल्य समझा , उसका उपयोग कर सकता है , और यह इरादा के अनुसार काम करेगा ... उस दृष्टिकोण के साथ क्या गलत है?



3
यहां व्यवहार के लिए एक विशेष मामले को परिभाषित करने से क्या लाभ है? ज़रूर, हमारे सभी कार्यक्रमों और पुस्तकालयों को बड़ा और धीमा बनाने देता है क्योंकि @ मेहरदाद एक विशिष्ट और दुर्लभ मामले में एक चर को शुरू करने से बचना चाहता है।
पॉल टॉम्बलिन

9
@ W'rkncacnter मैं इससे सहमत नहीं हूं कि मैं एक डूप है। भले ही यह क्या मूल्य लेता है, ओपी को उम्मीद है कि यह शून्य हो जाएगा x -= x। सवाल यह है कि सभी में एकतरफा मानों तक पहुंच क्यों यूबी है।
23

6
यह दिलचस्प है कि कथन x = 0; आम तौर पर एक्सोर एक्स, असेंबली में एक्स में बदल जाता है। यह लगभग वही है जो आप यहाँ करने की कोशिश कर रहे हैं, लेकिन घटाव के बजाय एक्सोर के साथ।
0xFE

1
given अर्थात यहाँ व्यवहार को परिभाषित न करने से क्या लाभ है? '- मैंने सोचा होगा कि मानक का लाभ उन मूल्यों के अनन्तता को सूचीबद्ध न करने के साथ है जो स्पष्ट होने के लिए एक या अधिक चर पर निर्भर नहीं हैं। साथ ही, @Paul, मानक में इस तरह के बदलाव से प्रोग्राम और लाइब्रेरी को कोई बड़ा नहीं बनाया जा सकता है।
जिम बाल्टर 15'12

जवाबों:


90

हाँ, यह व्यवहार अपरिभाषित है, लेकिन विभिन्न कारणों से अधिकांश लोग इससे अवगत हैं।

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

जो व्यवहार को अपरिभाषित बनाता है, वह आपके चर की एक अतिरिक्त संपत्ति है, जिसका अर्थ है कि यह "के साथ घोषित किया जा सकता है" अर्थात registerइसका पता कभी नहीं लिया जाता है। ऐसे चर का विशेष रूप से इलाज किया जाता है क्योंकि ऐसे आर्किटेक्चर होते हैं जिनमें वास्तविक सीपीयू रजिस्टर होते हैं जो एक तरह की अतिरिक्त स्थिति होती है जो कि "अनइंस्टालिज्ड" होती है और जो कि प्रकार डोमेन में एक मूल्य के अनुरूप नहीं है।

संपादित करें: मानक का प्रासंगिक वाक्यांश 6.3.2.1p2 है:

यदि लवल्यू स्वचालित भंडारण अवधि की एक वस्तु को डिजाइन करता है जिसे रजिस्टर स्टोरेज क्लास के साथ घोषित किया जा सकता है (इसका पता कभी नहीं लिया गया था), और उस वस्तु को अनइंस्टाल्यूट किया गया है (प्रारंभिक के साथ घोषित नहीं किया गया है और इसका उपयोग करने से पहले कोई असाइनमेंट नहीं किया गया है ), व्यवहार अपरिभाषित है।

और इसे स्पष्ट करने के लिए, निम्नलिखित कोड सभी परिस्थितियों में कानूनी है:

  • यहाँ के पते aऔर bलिए गए हैं, इसलिए उनका मूल्य सिर्फ अनिश्चित है।
  • चूंकि unsigned charट्रैप अभ्यावेदन कभी नहीं होता है कि अनिश्चित मान सिर्फ अनिर्दिष्ट है, किसी भी मूल्य हो unsigned charसकता है।
  • अंत में मान रखना a चाहिए0

Edit2: a और bअनिर्दिष्ट मूल्य हैं:

3.19.3 संबंधित प्रकार का अनिर्दिष्ट मूल्य
मान्य मान जहां यह अंतर्राष्ट्रीय मानक कोई आवश्यकता नहीं लगाता है जिस पर किसी भी उदाहरण में मूल्य चुना जाता है


6
शायद मुझे कुछ याद आ रहा है, लेकिन मुझे लगता है कि unsignedनिश्चित रूप से ट्रैप प्रतिनिधित्व हो सकता है। क्या आप मानक के उस हिस्से की ओर इशारा कर सकते हैं जो ऐसा कहता है? मैं :6.2.6.2 / 1 में निम्नलिखित देखता हूं: " अहस्ताक्षरित चार के अलावा अन्य पूर्णांक प्रकारों के लिए, ऑब्जेक्ट्रेड्रिशन के बिट्स को दो समूहों में विभाजित किया जाएगा: मूल्य बिट्स और पैडिंग बिट्स (उत्तरार्द्ध की कोई आवश्यकता नहीं है)। ... यह मान प्रतिनिधित्व के रूप में जाना जाएगा। किसी भी पैडिंग बिट्स के मान अनिर्दिष्ट हैं। "" टिप्पणी के साथ कहा गया है: "पैडिंग बिट्स के कुछ संयोजन जाल प्रतिनिधित्व उत्पन्न कर सकते हैं"।
कोनियो

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

4
@conio आप इसके अलावा अन्य सभी प्रकार के लिए सही हैं unsigned char, लेकिन यह उत्तर उपयोग कर रहा है unsigned char। यद्यपि ध्यान दें: एक सख्ती से अनुरूप कार्यक्रम गणना कर सकता है sizeof(unsigned) * CHAR_BITऔर निर्धारित कर सकता है , इसके आधार पर UINT_MAX, उस विशेष कार्यान्वयन में संभवतः के लिए ट्रैप निरूपण नहीं हो सकता है unsigned। उस कार्यक्रम के बाद वह दृढ़ संकल्प हो गया, फिर वह वही करने के लिए आगे बढ़ सकता है जो यह उत्तर देता है unsigned char

4
@JensGustedt: memcpyएक व्याकुलता नहीं है, अर्थात यदि आपका उदाहरण अभी भी लागू नहीं होता तो इसे बदल दिया जाता *&a = *&b;
आर .. गिटहब स्टॉप हेल्पिंग ICE

4
@ आर .. मुझे यकीन नहीं हो रहा है। सी समिति की मेलिंग सूची पर एक निरंतर चर्चा चल रही है, और ऐसा लगता है कि यह सब एक बड़ी गड़बड़ी है, अर्थात् जो व्यवहार है (या किया गया है) के बीच एक बड़ा अंतर है और जो वास्तव में लिखा गया है। हालांकि जो स्पष्ट है, वह यह है कि मेमोरी को एक्सेस करना unsigned charऔर इस प्रकार memcpyमदद करता है, जिसके लिए *&कम स्पष्ट है। मैं एक बार यह रिपोर्ट करता हूँ।
जेन्स गुस्टेड

24

C मानक अनुकूलन करने के लिए बहुत सारे अक्षांशों को संकलक देता है। इन अनुकूलन के परिणाम आश्चर्यजनक हो सकते हैं यदि आप उन कार्यक्रमों के एक भोले मॉडल को मानते हैं जहां अनैतिक स्मृति कुछ यादृच्छिक बिट पैटर्न पर सेट होती है और उनके लिखे जाने के क्रम में सभी ऑपरेशन किए जाते हैं।

नोट: निम्नलिखित उदाहरण केवल मान्य हैं क्योंकि xइसका पता कभी नहीं लिया गया है, इसलिए यह "रजिस्टर-लाइक" है। यदि उनके xपास ट्रैप अभ्यावेदन का प्रकार है तो वे भी मान्य होंगे ; यह शायद ही कभी अहस्ताक्षरित प्रकारों के लिए होता है (इसमें कम से कम एक बिट भंडारण के लिए "बर्बाद करना" आवश्यक होता है, और इसे प्रलेखित किया जाना चाहिए), और इसके लिए असंभव है unsigned char। यदि xकोई हस्ताक्षरित प्रकार था, तो कार्यान्वयन बिट पैटर्न को परिभाषित कर सकता है जो कि एक संख्या नहीं है - (2 एन -1 -1) और 2 एन -1 -1 एक जाल प्रतिनिधित्व के रूप में। देखिए जेन्स गुस्तेद का जवाब

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

जब लाइन 3 का मूल्यांकन किया जाता है, तो xइसे अभी तक आरंभ नहीं किया जाता है, इसलिए (कंपाइलर का कारण) लाइन 3 कुछ प्रकार की होनी चाहिए, जो अन्य स्थितियों के कारण नहीं हो सकती है जो संकलक का पता लगाने के लिए पर्याप्त स्मार्ट नहीं था। चूंकि zलाइन 4 के बाद उपयोग नहीं किया जाता है, और xलाइन 5 से पहले उपयोग नहीं किया जाता है, इसलिए समान रजिस्टर का उपयोग दोनों चर के लिए किया जा सकता है। इसलिए इस छोटे से कार्यक्रम को रजिस्टरों के निम्नलिखित कार्यों के लिए संकलित किया गया है:

का अंतिम मान xअंतिम मान है r0, और अंतिम मूल्य का yअंतिम मूल्य है r1। ये मान x = -3 और y = -4 हैं, और 5 और 4 नहीं हैं जैसा कि अगर xठीक से आरंभीकृत किया गया होता ।

अधिक विस्तृत उदाहरण के लिए, निम्नलिखित कोड के टुकड़े पर विचार करें:

मान लीजिए कि संकलक पता लगाता है कि conditionकोई दुष्प्रभाव नहीं है। चूंकि conditionसंशोधित नहीं होता है x, इसलिए कंपाइलर जानता है कि लूप के माध्यम से पहला रन संभवत: एक्सेस नहीं किया जा सकता है xक्योंकि यह अभी तक आरंभीकृत नहीं है। इसलिए लूप बॉडी का पहला निष्पादन के बराबर है x = some_value(), हालत का परीक्षण करने की कोई आवश्यकता नहीं है। कंपाइलर इस कोड को संकलित कर सकता है जैसे कि आपने लिखा है

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

  • पहले लूप पुनरावृत्ति के दौरान, xसमय -xका मूल्यांकन किया जाता है।
  • -x अपरिभाषित व्यवहार किया है, इसलिए इसका मूल्य जो भी है-सुविधाजनक है।
  • अनुकूलन नियम लागू होता है, इसलिए इस कोड को सरल बनाया जा सकता है ।condition ? value : valuecondition; value

जब आपके प्रश्न में कोड के साथ सामना किया जाता है, तो यह उसी संकलक का विश्लेषण करता है कि जब x = - xमूल्यांकन किया जाता है, तो -xजो कुछ भी है वह सुविधाजनक है। तो असाइनमेंट दूर अनुकूलित किया जा सकता है।

मैंने एक संकलक के उदाहरण की तलाश नहीं की है जो ऊपर वर्णित के अनुसार व्यवहार करता है, लेकिन यह उस तरह का अनुकूलन है जो अच्छे संकलक करने की कोशिश करते हैं। मैं एक का सामना करने के लिए आश्चर्यचकित नहीं होगा। यहां एक संकलक का कम प्रशंसनीय उदाहरण है जिसके साथ आपका प्रोग्राम क्रैश हो जाता है। (यदि आप किसी तरह के उन्नत डिबगिंग मोड में अपने प्रोग्राम को संकलित करते हैं, तो ऐसा नहीं हो सकता है।)

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


+1 अच्छा स्पष्टीकरण, मानक उस स्थिति का विशेष ध्यान रख रहा है। उस कहानी की निरंतरता के लिए नीचे मेरा उत्तर देखें। (टिप्पणी के रूप में बहुत लंबा है)।
जेन्स गुस्तेद

@JensGustedt ओह, आपका जवाब एक महत्वपूर्ण बिंदु बनाता है जिसे मैंने (और अन्य) याद किया: जब तक कि प्रकार में ट्रैप मान नहीं होते हैं, जिसके लिए एक अहस्ताक्षरित प्रकार के लिए कम से कम एक बिट "बर्बाद" करने की आवश्यकता होती है, xएक असमान मूल्य होता है लेकिन एक्सेस करने पर व्यवहार होता परिभाषित किया जा सकता है अगर x में रजिस्टर जैसा व्यवहार नहीं था।
गिलेस एसओ- बुराई को रोकना '

@ गिल्स: कम से कम क्लैंग आपके द्वारा बताए गए अनुकूलन के प्रकार बनाता है: (1) , (2) , (3)
व्लाद

1
उस फैशन में क्लैंग प्रोसेस चीजों के होने का क्या व्यावहारिक लाभ है? यदि डाउनस्ट्रीम कोड कभी भी मूल्य का उपयोग नहीं करता है x, तो उस पर सभी कार्यों को छोड़ दिया जा सकता है, चाहे उसका मूल्य परिभाषित किया गया हो या नहीं। यदि कोड निम्न उदाहरण if (volatile1) x=volatile2; ... x = (x+volatile3) & 255;किसी भी मान 0-255 के साथ समान रूप से खुश होगा xजो उस मामले में हो सकता है जहां volatile1शून्य उत्पन्न हुआ था, तो मुझे लगता है कि एक कार्यान्वयन होगा जो प्रोग्रामर को एक अनावश्यक लिखने से चूकने की अनुमति देगा, xजिसे एक से अधिक गुणवत्ता माना जाना चाहिए व्यवहार करेगा ...
20

... उस मामले में पूरी तरह से अप्रत्याशित फैशन में। एक कार्यान्वयन जो उस मामले में एक कार्यान्वयन-परिभाषित जाल को मज़बूती से बढ़ाएगा, कुछ उद्देश्यों के लिए, अभी तक उच्च गुणवत्ता वाला माना जा सकता है, लेकिन पूरी तरह से अप्रत्याशित व्यवहार करना मुझे किसी भी उद्देश्य के लिए सबसे कम गुणवत्ता वाले व्यवहार की तरह लगता है।
सुपरकैट

16

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

(6.2.6.1 देर से C11 मसौदे में कहा गया है) कुछ वस्तु प्रतिनिधित्वों को वस्तु प्रकार के मूल्य का प्रतिनिधित्व नहीं करना चाहिए। यदि किसी वस्तु के संग्रहित मूल्य में ऐसा प्रतिनिधित्व होता है और उसे एक वर्णनात्मक अभिव्यक्ति द्वारा पढ़ा जाता है जिसमें वर्ण प्रकार नहीं होता है, तो व्यवहार अपरिभाषित होता है। यदि इस तरह के प्रतिनिधित्व को एक साइड इफेक्ट द्वारा उत्पादित किया जाता है जो वस्तु के सभी या किसी हिस्से को एक वर्णनात्मक अभिव्यक्ति द्वारा संशोधित करता है जिसमें चरित्र प्रकार नहीं होता है, तो व्यवहार अपरिभाषित 50 है) इस तरह के प्रतिनिधित्व को एक ट्रैप प्रतिनिधित्व कहा जाता है।

(यह स्पष्टीकरण केवल उन प्लेटफार्मों पर लागू होता है, जहां unsigned intट्रैप अभ्यावेदन हो सकते हैं, जो वास्तविक विश्व प्रणालियों पर दुर्लभ है। वैकल्पिक और शायद अधिक सामान्य कारणों के लिए विवरण और संदर्भ के लिए टिप्पणियां देखें जो मानक के वर्तमान शब्द को आगे बढ़ाते हैं।)


3
@VladLazarenko: यह सी के बारे में है, विशेष रूप से सीपीयू नहीं। कोई भी तुच्छ रूप से सीपीयू को डिज़ाइन कर सकता है जिसमें पूर्णांक के लिए बिट पैटर्न होता है जो इसे पागल करता है। एक सीपीयू पर विचार करें, जिसके रजिस्टरों में "पागल बिट" है।
डेविड Schwartz

2
तो क्या मैं यह कह सकता हूं कि पूर्णांक और x86 के मामले में व्यवहार को अच्छी तरह से परिभाषित किया गया है?

3
ठीक है, सैद्धांतिक रूप से आपके पास एक कंपाइलर हो सकता है जिसने केवल 28-बिट पूर्णांक (x86 पर) का उपयोग करने का फैसला किया है और प्रत्येक जोड़, गुणन (एक आगे) को संभालने के लिए विशिष्ट कोड जोड़ा है और सुनिश्चित करें कि ये 4 बिट अप्रयुक्त हैं (या एक SIGSEGV का उत्सर्जन करें अन्यथा) )। एक अनजान मूल्य इसका कारण बन सकता है।
eq- 23

4
मुझे नफरत है जब कोई व्यक्ति हर किसी का अपमान करता है क्योंकि कोई इस मुद्दे को नहीं समझता है। क्या व्यवहार अपरिभाषित है या नहीं यह पूरी तरह से मानक का कहना है कि एक मामला है। ओह, और eq के परिदृश्य के बारे में व्यावहारिक रूप से कुछ भी नहीं है ... यह पूरी तरह से वंचित है।
जिम बाल्टर 15'12

7
@ व्लाद लाजेंको: इटेनियम सीपीयू में प्रत्येक पूर्णांक रजिस्टर के लिए एक NaT (नॉट ए थिंग) ध्वज होता है। NaT फ्लैग का उपयोग सट्टा निष्पादन को नियंत्रित करने के लिए किया जाता है और यह रजिस्टरों में घूम सकता है जो उपयोग से पहले ठीक से शुरू नहीं किया गया है। एक NaT बिट सेट के साथ इस तरह के रजिस्टर से पढ़ना एक अपवाद पैदा करता है। देखें blogs.msdn.com/b/oldnewthing/archive/2004/01/19/60162.aspx
नॉर्डिक मेनफ्रेम

13

(यह उत्तर सी 1999 को संबोधित करता है। सी 2011 के लिए, जेन्स गुस्तेद का जवाब देखें।)

सी मानक यह नहीं कहता है कि स्वचालित भंडारण अवधि की एक वस्तु के मूल्य का उपयोग जो कि आरंभिक नहीं है अपरिभाषित व्यवहार है। सी 1999 मानक मानक 6.7.8 10 में कहता है, "यदि किसी वस्तु की स्वचालित भंडारण अवधि स्पष्ट रूप से प्रारंभ नहीं की गई है, तो इसका मूल्य अनिश्चित है।" (यह पैराग्राफ यह परिभाषित करने के लिए जाता है कि स्थैतिक वस्तुओं को कैसे आरम्भ किया जाता है, इसलिए एकमात्र असंगठित वस्तुएं जिनके बारे में हम चिंतित हैं, वे स्वचालित वस्तुएँ हैं।)

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

इसलिए, यदि असिंचित unsigned int xका अनिर्दिष्ट मूल्य है, तो x -= xशून्य का उत्पादन करना चाहिए। यह सवाल छोड़ देता है कि क्या यह एक ट्रैप प्रतिनिधित्व हो सकता है। एक जाल मूल्य तक पहुँचने के लिए 6.2.6.1 5 प्रति अपरिभाषित व्यवहार होता है।

कुछ प्रकार की वस्तुओं में ट्रैप अभ्यावेदन हो सकते हैं, जैसे फ्लोटिंग-पॉइंट संख्याओं के संकेतन NaN। लेकिन अहस्ताक्षरित पूर्णांक विशेष हैं। 6.2.6.2 के अनुसार, एक अहस्ताक्षरित इंट के एन मान बिट्स में से प्रत्येक 2 की शक्ति का प्रतिनिधित्व करता है, और मूल्य बिट्स के प्रत्येक संयोजन 0 से 2 एन -1 के मूल्यों में से एक का प्रतिनिधित्व करता है । इसलिए अहस्ताक्षरित पूर्णांकों में केवल उनके पैडिंग बिट्स (जैसे समता बिट) में कुछ मूल्यों के कारण ट्रैप अभ्यावेदन हो सकते हैं।

यदि, आपके लक्षित प्लेटफ़ॉर्म पर, एक अहस्ताक्षरित int में कोई पैडिंग बिट्स नहीं हैं, तो एक अनइंस्टाल्यूट किए गए अहस्ताक्षरित int में ट्रैप प्रतिनिधित्व नहीं हो सकता है, और इसके मूल्य का उपयोग करने से अपरिभाषित व्यवहार नहीं हो सकता है।


यदि xएक जाल प्रतिनिधित्व है, तो x -= xफंस सकता है, है ना? फिर भी, बिना किसी अतिरिक्त बिट्स वाले अहस्ताक्षरित पूर्णांक को इंगित करने के लिए +1 ने व्यवहार को परिभाषित किया होगा - यह स्पष्ट रूप से अन्य उत्तरों के विपरीत है और (उद्धरण के अनुसार) यह प्रतीत होता है कि मानक क्या है।
user541686

हां, यदि किसी प्रकार का xट्रैप प्रतिनिधित्व है, तो x -= xवह फंस सकता है। यहां तक ​​कि बस xएक मूल्य के रूप में इस्तेमाल किया जा सकता है। (यह xएक लैवल्यू के रूप में उपयोग करने के लिए सुरक्षित है , एक वस्तु में लिखना एक ट्रैप प्रतिनिधित्व से प्रभावित नहीं होगा जो इसमें है।)
एरिक पोस्टपिसिल

अहस्ताक्षरित प्रकारों में शायद ही कभी एक जाल प्रतिनिधित्व होता है
जेन्स गुस्टेड

रेमंड चेन का हवाला देते हुए , "ia64 पर, प्रत्येक 64-बिट रजिस्टर वास्तव में 65 बिट्स है। अतिरिक्त बिट को" NaT "कहा जाता है जो" नहीं बात नहीं "के लिए खड़ा है। बिट सेट है जब रजिस्टर में एक वैध मूल्य नहीं होता है। इसे फ़्लोटिंग पॉइंट NaN के पूर्णांक संस्करण के रूप में सोचें। ... यदि आपके पास एक रजिस्टर है जिसका मूल्य NaT है और आप इस पर बहुत गलत तरीके से साँस लेते हैं (उदाहरण के लिए, स्मृति को इसके मूल्य को बचाने की कोशिश करें), प्रोसेसर एक STATUS_REG_NAT_CONSUMPTION अपवाद बढ़ाएगा "। यानी, एक जाल बिट पूरी तरह से मूल्य के बाहर हो सकता है।
चीयर्स एंड हीथ। - अल्फ

−1 कथन "यदि आपके लक्ष्य प्लेटफ़ॉर्म पर, एक अहस्ताक्षरित int में कोई पेडिंग बिट्स नहीं है, तो एक अनइंस्टाल्यूट किए गए अहस्ताक्षरित int में ट्रैप प्रतिनिधित्व नहीं हो सकता है, और इसके मान का उपयोग करने से अपरिभाषित व्यवहार नहीं हो सकता है।" x64 NaT बिट्स जैसी योजनाओं पर विचार करने में विफल रहता है।
चीयर्स एंड हीथ। - अल्फ

11

हां, यह अपरिभाषित है। कोड क्रैश हो सकता है। C का कहना है कि व्यवहार अपरिभाषित है क्योंकि सामान्य नियम को अपवाद बनाने का कोई विशेष कारण नहीं है। यह लाभ अपरिभाषित व्यवहार के अन्य मामलों के समान ही है - संकलक को इस कार्य को करने के लिए विशेष कोड का उत्पादन करने की आवश्यकता नहीं है।

स्पष्ट रूप से, कंपाइलर बस चर के अंदर "काम" के रूप में जो भी कचरा मूल्य समझा, उसका उपयोग कर सकता है, और यह इरादा के अनुसार काम करेगा ... उस दृष्टिकोण के साथ क्या गलत है?

आपको क्यों लगता है कि ऐसा नहीं होता है? ठीक यही तरीका अपनाया गया। संकलक को इसे काम करने की आवश्यकता नहीं है, लेकिन इसे विफल करने के लिए आवश्यक नहीं है।


1
संकलक के पास इसके लिए विशेष कोड नहीं है, हालाँकि। बस स्थान आवंटित करना (हमेशा की तरह) और चर को गहन नहीं करना इसे सही व्यवहार देता है। मुझे नहीं लगता कि विशेष तर्क की आवश्यकता है।
user541686

7
1) यकीन है, वे हो सकता है। लेकिन मैं ऐसे किसी तर्क के बारे में नहीं सोच सकता, जो इसे और बेहतर बनाए। 2) प्लेटफ़ॉर्म जानता है कि अनइंस्टॉल किए गए मेमोरी के मूल्य पर भरोसा नहीं किया जा सकता है, इसलिए इसे बदलने के लिए स्वतंत्र है। उदाहरण के लिए, यह पृष्ठभूमि में असंबद्ध स्मृति को शून्य कर सकता है जब जरूरत पड़ने पर उपयोग के लिए तैयार पृष्ठों को शून्य कर सकता है। (विचार करें कि क्या ऐसा होता है: 1) हम घटाना मान पढ़ते हैं, कहते हैं कि हमें 3. मिलता है। पेज शून्य हो जाता है क्योंकि यह असिंचित है, मान को 0. 3 में बदलना) हम एक परमाणु घटाव करते हैं, पृष्ठ को आवंटित करते हैं और बनाते हैं। मान -3। उफ़।)
डेविड श्वार्ट्ज

2
-1 क्योंकि आप अपने दावे के लिए कोई औचित्य नहीं देते हैं। ऐसी परिस्थितियां हैं जहां यह अपेक्षा करना मान्य होगा कि कंपाइलर केवल उस मान को लेता है जो मेमोरी लोकेशन में लिखा गया है।
जेन्स गुस्टेड

1
@JensGustedt: मुझे आपकी टिप्पणी समझ में नहीं आती। क्या आप स्पष्ट कर सकते हैं?
डेविड श्वार्ट्ज

3
क्योंकि आप केवल यह दावा करते हैं कि एक सामान्य नियम है, इसे संदर्भित किए बिना। जैसा कि यह "प्राधिकरण द्वारा प्रमाण" का एक प्रयास है, जो कि मुझे एसओ पर उम्मीद नहीं है। और प्रभावी ढंग से बहस नहीं करने के लिए कि यह एक अनिर्दिष्ट मूल्य क्यों नहीं हो सकता है। एकमात्र कारण यह है कि यह सामान्य मामले में यूबी है जो कि xघोषित किया जा सकता है register, अर्थात इसका पता कभी नहीं लिया जाता है। मुझे नहीं पता कि क्या आप इसके बारे में जानते थे (यदि, आप इसे प्रभावी ढंग से छिपा रहे थे), लेकिन एक सही उत्तर का उल्लेख करना होगा।
जेन्स गुस्टेड

7

किसी भी प्रकार के किसी भी चर के लिए, जो कि आरंभिक नहीं है या अन्य कारणों से एक अनिश्चित मान रखता है, निम्नलिखित कोड के लिए लागू होता है:

  • यदि वैरिएबल में स्वचालित संग्रहण अवधि है और उसका पता नहीं है, तो कोड हमेशा अपरिभाषित व्यवहार [1] को आमंत्रित करता है।
  • अन्यथा, यदि सिस्टम दिए गए वैरिएबल प्रकार के लिए ट्रैप अभ्यावेदन का समर्थन करता है, तो कोड हमेशा अपरिभाषित व्यवहार को आमंत्रित करता है [2]।
  • अन्यथा यदि कोई ट्रैप प्रतिनिधित्व नहीं हैं, तो चर अनिर्दिष्ट मूल्य लेता है। इस बात की कोई गारंटी नहीं है कि चर पढ़ने के बाद यह अनिर्दिष्ट मूल्य सुसंगत है। हालांकि, यह एक ट्रैप प्रतिनिधित्व नहीं होने की गारंटी है और इसलिए यह अपरिभाषित व्यवहार न करने की गारंटी है [3]।

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


[१]: सी ११ ६.३.२.१:

यदि लवल्यू स्वचालित भंडारण अवधि की एक वस्तु को डिजाइन करता है जिसे रजिस्टर स्टोरेज क्लास के साथ घोषित किया जा सकता है (इसका पता कभी नहीं लिया गया था), और उस वस्तु को अनइंस्टाल्यूट किया गया है (प्रारंभिक के साथ घोषित नहीं किया गया है और इसका उपयोग करने से पहले कोई असाइनमेंट नहीं किया गया है ), व्यवहार अपरिभाषित है।

[२]: सी ११ ६.२.६.१:

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

[३] सी ११:

3.19.2
अनिश्चित मान
या तो अनिर्दिष्ट मूल्य या जाल प्रतिनिधित्व है

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

3.19.4
ट्रैप प्रतिनिधित्व
एक वस्तु प्रतिनिधित्व है जिसे ऑब्जेक्ट प्रकार के मूल्य का प्रतिनिधित्व करने की आवश्यकता नहीं है


3
@Vality वास्तविक दुनिया में, सभी कंप्यूटरों का 99.9999% ट्रैप अभ्यावेदन के बिना दो पूरक सीपीयू हैं। इसलिए कोई ट्रैप प्रतिनिधित्व नहीं है और ऐसे वास्तविक दुनिया के कंप्यूटरों पर व्यवहार की चर्चा करना अत्यधिक प्रासंगिक है। यह मान लेना कि बेतहाशा विदेशी कंप्यूटर मानदंड मददगार नहीं है। वास्तविक दुनिया में ट्रैप अभ्यावेदन इतने दुर्लभ हैं कि मानक में ट्रैप प्रतिनिधित्व की उपस्थिति को ज्यादातर 1980 के दशक से विरासत में मिला मानक दोष माना जाता है। के रूप में एक के पूरक और साइन और परिमाण कंप्यूटर के लिए समर्थन है।
लंडिन

3
वैसे, यह एक उत्कृष्ट कारण है कि stdint.hहमेशा सी के मूल प्रकारों के बजाय उपयोग किया जाना चाहिए क्योंकि stdint.h2 के पूरक और कोई पैड बिट्स को लागू नहीं करता है। दूसरे शब्दों में, stdint.hप्रकारों को बकवास से भरा होने की अनुमति नहीं है।
लंडिन

2
फिर से दोषपूर्ण रिपोर्ट पर समिति की प्रतिक्रिया कहती है कि: "प्रश्न 2 का उत्तर यह है कि अनिश्चित मान पर किए गए किसी भी कार्य का एक अनिश्चित परिणाम के रूप में अनिश्चित मान होगा।" और "प्रश्न 3 का उत्तर यह है कि पुस्तकालय के कार्य अपरिभाषित मूल्यों पर उपयोग किए जाने पर अपरिभाषित व्यवहार प्रदर्शित करेंगे।"
अंती हापला

2
DRs

1
@AnttiHaapala हाँ मुझे पता है कि डॉ। यह इस उत्तर का खंडन नहीं करता है। एक असंबद्ध स्मृति स्थान को पढ़ते समय आपको एक अनिश्चित मूल्य मिल सकता है और जरूरी नहीं कि हर बार एक ही मूल्य हो। लेकिन वह अनिर्दिष्ट व्यवहार है, अपरिभाषित व्यवहार नहीं ।
लुंडिन

2

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

एआरएम जैसे प्लेटफॉर्म के लिए एक कंपाइलर जहां 32-बिट रजिस्टरों पर लोड और स्टोर के अलावा अन्य सभी निर्देश यथोचित रूप से कोड को फैशन के बराबर प्रोसेस कर सकते हैं:

यदि या तो वाष्पशील एक गैर-शून्य मान प्राप्त करता है, तो r0 0 मान में लोड किया जाएगा ... 65535। अन्यथा जब यह कहा जाता है तो यह जो भी आयोजित करेगा उसे उपज देगा (अर्थात x में दिया गया मान), जिसका मान 0..65535 सीमा में नहीं हो सकता है। मानक के पास मूल्य के व्यवहार का वर्णन करने के लिए किसी भी शब्दावली का अभाव है जिसका प्रकार uint16_t है, लेकिन जिसका मूल्य 0..65535 की सीमा के बाहर है, सिवाय इसके कि कोई कार्रवाई जो ऐसे व्यवहार का उत्पादन कर सकती है, वह यूबी को आमंत्रित करता है।


दिलचस्प। तो क्या आप कह रहे हैं कि स्वीकृत उत्तर गलत है? या आप कह रहे हैं कि यह सिद्धांत में सही है लेकिन व्यवहार में संकलनकर्ता अजीब चीजें कर सकते हैं?
user541686

@ मेहरदाद: कार्यान्वयन के लिए ऐसा व्यवहार होना आम है जो यूबी के अभाव में संभव हो सकता है। मुझे लगता है कि यह सहायक होगा यदि मानक ने आंशिक रूप से अनिश्चित मूल्य की अवधारणा को मान्यता दी है जिसका "आवंटित" बिट्स एक फैशन में व्यवहार करेगा, जो कि सबसे खराब, अनिर्दिष्ट है, लेकिन अतिरिक्त ऊपरी बिट्स के साथ गैर-नियतात्मक रूप से व्यवहार करता है (जैसे कि यदि उपरोक्त फ़ंक्शन का परिणाम प्रकार के चर में संग्रहीत किया जाता है uint16_t, वह चर कभी-कभी 123 और कभी-कभी 6553623 के रूप में पढ़ा जा सकता है)। अगर परिणाम को नजरअंदाज किया जा रहा है ...
सुपरकैट

... या इस तरह से उपयोग किया जाता है कि किसी भी संभव तरीके से इसे पढ़ा जा सकता है सभी अंतिम परिणाम बैठक की आवश्यकताओं को पूरा करेंगे, आंशिक रूप से अनिश्चित मूल्य का अस्तित्व एक समस्या नहीं होनी चाहिए। दूसरी ओर, मानक में ऐसा कुछ भी नहीं है जो किसी भी परिस्थिति में आंशिक-अनिश्चित मूल्यों के अस्तित्व के लिए अनुमति देगा जहां मानक किसी भी व्यवहार संबंधी आवश्यकताओं को लागू करेगा।
सुपरकैट

यह मुझे लगता है कि आप जो वर्णन कर रहे हैं, वह वही है जो स्वीकृत उत्तर में है - कि अगर एक चर के साथ घोषित किया जा सकता है register, तो इसमें अतिरिक्त बिट्स हो सकते हैं जो व्यवहार को अपरिभाषित बनाते हैं। यह वही है जो आप कह रहे हैं, है ना?
user541686

@ मेहरदाद: स्वीकृत उत्तर उन आर्किटेक्चर पर केंद्रित है, जिनके रजिस्टरों में एक अतिरिक्त "अनइंस्टाल्यूटेड" स्थिति होती है, और यदि एक अनइंस्टॉल किए गए रजिस्टर को लोड किया जाता है तो जाल। ऐसे आर्किटेक्चर मौजूद हैं, लेकिन आम नहीं हैं। मैं एक ऐसे परिदृश्य का वर्णन करता हूं, जहां सामान्य हार्डवेयर व्यवहार प्रदर्शित कर सकता है, जो कि सी स्टैंडर्ड द्वारा चिंतनित किसी भी चीज़ के दायरे से बाहर है, लेकिन यदि कंपाइलर मिश्रण में अपना अतिरिक्त अपव्यय नहीं करता है, तो उपयोगी रूप से विवश होगा। उदाहरण के लिए, यदि किसी फ़ंक्शन के पास एक पैरामीटर है जो प्रदर्शन करने के लिए एक ऑपरेशन का चयन करता है, और कुछ ऑपरेशन उपयोगी डेटा लौटाते हैं, लेकिन अन्य नहीं ...
सुपरकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.