c++ - हस्ताक्षरित पूर्णांक अतिप्रवाह परिभाषित व्यवहार क्यों है लेकिन हस्ताक्षर पूर्णांक ओवरफ़्लो नहीं है?




undefined-behavior integer-overflow (4)

बिना हस्ताक्षर किए पूर्णांक ओवरफ्लो को सी और सी ++ मानकों दोनों द्वारा अच्छी तरह परिभाषित किया गया है। उदाहरण के लिए, सी 99 मानक ( §6.2.5/9 ) राज्यों

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

हालांकि, दोनों मानकों का कहना है कि हस्ताक्षर पूर्णांक ओवरफ्लो अपरिभाषित व्यवहार है। फिर, सी 99 मानक से ( §3.4.3/1 )

अवांछित व्यवहार का एक उदाहरण फ्लो ओउ पर पूर्णांक पर व्यवहार है

क्या इस विसंगति के लिए कोई तकनीकी कारण है (यहां तक ​​कि बेहतर!)?


उल्लिखित अन्य मुद्दों के अलावा, बिना हस्ताक्षर किए गए गणित लपेटने से अनगिनत पूर्णांक प्रकार अमूर्त बीजगणितीय समूहों के रूप में व्यवहार करते हैं (जिसका अर्थ है कि, अन्य चीजों के साथ, मूल्य X और Y की किसी भी जोड़ी के लिए, कुछ अन्य मूल्य Z मौजूद होंगे जैसे X+Z , अगर सही ढंग से कास्ट किया जाएगा, बराबर Y और YZ होगा, अगर सही ढंग से कास्ट किया गया है, तो बराबर X )। यदि हस्ताक्षरित मान केवल स्टोरेज-लोकेशन प्रकार थे और इंटरमीडिएट-एक्सप्रेशन प्रकार नहीं थे (उदाहरण के लिए यदि सबसे बड़े पूर्णांक प्रकार के हस्ताक्षर किए गए समकक्ष नहीं थे, और बिना हस्ताक्षर किए गए प्रकारों पर अंकगणितीय परिचालनों का व्यवहार किया गया था, हालांकि वे पहले उन्हें बड़े हस्ताक्षरित प्रकारों में परिवर्तित कर चुके थे, फिर वहां परिभाषित रैपिंग व्यवहार के लिए उतनी आवश्यकता नहीं होगी, लेकिन एक प्रकार में गणना करना मुश्किल है, जिसमें एक additive उलटा नहीं है।

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


ऐतिहासिक कारण यह है कि अधिकांश सी कार्यान्वयन (कंपाइलर्स) ने जो भी ओवरफ्लो व्यवहार का उपयोग किया था, वह पूर्णांक प्रतिनिधित्व के साथ लागू करने के लिए सबसे आसान था। सी कार्यान्वयन आमतौर पर सीपीयू द्वारा उपयोग किए जाने वाले समान प्रतिनिधित्व का उपयोग करते हैं - इसलिए सीपीयू द्वारा उपयोग किए गए पूर्णांक प्रतिनिधित्व से ओवरफ्लो व्यवहार का पालन किया जाता है।

व्यवहार में, यह केवल हस्ताक्षरित मूल्यों के लिए प्रतिनिधित्व है जो कार्यान्वयन के अनुसार भिन्न हो सकते हैं: एक का पूरक, दो पूरक, साइन-आयाम। एक हस्ताक्षरित प्रकार के लिए मानक को भिन्नता की अनुमति देने का कोई कारण नहीं है क्योंकि केवल एक स्पष्ट बाइनरी प्रतिनिधित्व होता है (मानक केवल बाइनरी प्रतिनिधित्व की अनुमति देता है)।

प्रासंगिक उद्धरण:

सी 99 6.2.6.1:3 :

हस्ताक्षरित बिट-फ़ील्ड में संग्रहीत मान और बिना हस्ताक्षर किए गए चार प्रकार के ऑब्जेक्ट्स को शुद्ध बाइनरी नोटेशन का उपयोग करके दर्शाया जाएगा।

सी 99 6.2.6.2 एसएमएस :

यदि साइन बिट एक है, तो मान निम्न तरीकों में से एक में संशोधित किया जाएगा:

- साइन बिट 0 के साथ संबंधित मान अस्वीकार किया गया है ( साइन और परिमाण );

- साइन बिट में मूल्य है - (2 एन ) ( दो पूरक );

- साइन बिट में मूल्य है - (2 एन -1) ( एक पूरक )।

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


शायद एक और कारण है कि क्यों हस्ताक्षरित अंकगणित परिभाषित किया गया है क्योंकि हस्ताक्षरित संख्या पूर्णांक मॉड्यूलो 2 ^ n बनाते हैं, जहां n हस्ताक्षरित संख्या की चौड़ाई है। असाइन किए गए नंबर केवल दशमलव अंकों के बजाय बाइनरी अंकों का उपयोग करके पूर्णांक हैं। मॉड्यूलस सिस्टम में मानक संचालन करना अच्छी तरह से समझा जाता है।

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

दो पूरक पूरक कुछ परिचालनों को द्विआधारी प्रारूप में अधिक समझने की अनुमति देता है। उदाहरण के लिए, ऋणात्मक संख्या में वृद्धि समान है कि सकारात्मक संख्याओं के लिए (अतिप्रवाह स्थितियों के तहत अपेक्षा करें)। मशीन स्तर पर कुछ ऑपरेशन हस्ताक्षरित और हस्ताक्षरित संख्याओं के लिए समान हो सकते हैं। हालांकि, उन परिचालनों के परिणाम की व्याख्या करते समय, कुछ मामलों को समझ में नहीं आता - सकारात्मक और नकारात्मक अतिप्रवाह। इसके अलावा, ओवरफ्लो परिणाम अंतर्निहित हस्ताक्षरित प्रतिनिधित्व के आधार पर भिन्न होते हैं।


सबसे पहले, कृपया ध्यान दें कि सी 11 3.4.3, सभी उदाहरणों और पैर नोट्स की तरह, मानक पाठ नहीं है और इसलिए उद्धरण के लिए प्रासंगिक नहीं है!

प्रासंगिक पाठ जो बताता है कि पूर्णांक और फ्लोट का अतिप्रवाह अनिश्चित व्यवहार है यह है:

सी 11 6.5 / 5

यदि एक असाधारण स्थिति अभिव्यक्ति के मूल्यांकन के दौरान होती है (यानी, यदि परिणाम गणितीय रूप से परिभाषित नहीं है या इसके प्रकार के लिए प्रतिनिधित्व योग्य मानों की सीमा में नहीं है), व्यवहार अपरिभाषित है।

हस्ताक्षर किए गए पूर्णांक प्रकारों के व्यवहार के बारे में एक स्पष्टीकरण विशेष रूप से यहां पाया जा सकता है:

सी 11 6.2.5 / 9

एक हस्ताक्षरित पूर्णांक प्रकार के nonnegative मानों की सीमा संबंधित हस्ताक्षरित पूर्णांक प्रकार का एक subrange है, और प्रत्येक प्रकार में एक ही मान का प्रतिनिधित्व समान है। हस्ताक्षर किए गए ऑपरेटरों से जुड़ी एक गणना कभी भी बहती नहीं जा सकती है, जिसके परिणामस्वरूप परिणामस्वरूप हस्ताक्षरित पूर्णांक प्रकार द्वारा प्रतिनिधित्व नहीं किया जा सकता है, जो मॉड्यूल को उस संख्या को कम कर देता है जो परिणामस्वरूप प्रकार के द्वारा सबसे बड़े मूल्य से अधिक होता है।

यह हस्ताक्षर पूर्णांक प्रकार एक विशेष मामला बनाता है।

यह भी ध्यान रखें कि अगर कोई प्रकार किसी हस्ताक्षरित प्रकार में परिवर्तित हो जाता है तो अपवाद होता है और पुराना मान अब प्रदर्शित नहीं किया जा सकता है। व्यवहार केवल कार्यान्वयन-परिभाषित किया जाता है, हालांकि एक संकेत उठाया जा सकता है।

सी 11 6.3.1.3

6.3.1.3 हस्ताक्षरित और हस्ताक्षरित पूर्णांक

जब पूर्णांक प्रकार वाले मान को _Bool के अलावा किसी अन्य पूर्णांक प्रकार में परिवर्तित किया जाता है, यदि मान को नए प्रकार से दर्शाया जा सकता है, तो यह अपरिवर्तित है।

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

अन्यथा, नया प्रकार हस्ताक्षरित है और इसमें मूल्य का प्रतिनिधित्व नहीं किया जा सकता है; या तो परिणाम कार्यान्वयन-परिभाषित या कार्यान्वयन-परिभाषित संकेत उठाया गया है।





integer-overflow