2015-02-28 12 views
5
void swap(int* a, int* b) { 
    if (a != b) 
     *a ^= *b ^= *a ^= *b; 
} 

ऊपर *a ^= *b ^= *a ^= *b के रूप में सिर्फ *a = *a^(*b = *b^(*a = *a^*b)) के लिए एक शॉर्टकट है, कर सकता है (उदाहरण के लिए) 2 *a (XOR के लिए) बस से पहले 3 *a (=) के द्वारा संशोधित किया गया है मूल्यांकन किया जाना?एक्सओआर स्वैप एल्गोरिदम में ऑपरेटरों के अपरिभाषित व्यवहार?

क्या इससे कोई फर्क पड़ता है कि मैं इसे सी 99/सी 11/सी ++ 98/सी ++ 11 में लिखता हूं?

+0

मैं यहाँ के बारे में इस C11 में नए अनुक्रमण शासन के साथ की अनुमति है या एक चर्चा याद है। सी 99 में, यह स्पष्ट रूप से अपरिभाषित है ('* ए' को अनुक्रम बिंदु के बिना दो बार संशोधित किया गया है)। – mafso

+1

मुझे याद है कि सी ++ अपने असाइनमेंट ऑपरेटरों पर कुछ अतिरिक्त अनुक्रमिक गारंटी देता है, क्योंकि सी असाइनमेंट ऑपरेटर मूल्य वापस कर देते हैं, लेकिन सी ++ असाइनमेंट ऑपरेटर अंतराल लौटाते हैं, और बाद के अंतराल से लेकर रावल्यू रूपांतरण में अच्छी तरह से परिभाषित व्यवहार होना चाहिए। नतीजा * हो सकता है कि यह सी ++ में मान्य है, लेकिन मुझे यकीन नहीं है। – hvd

+0

@ एचवीडी: सी 11 ने थ्रेडिंग मानकीकरण के कारण सी ++ अनुक्रमण मॉडल अपनाया। एक असाइनमेंट के एलएचएस का संशोधन अब एलएचएस और आरएचएस के मूल्यांकन के बाद अनुक्रमित किया गया है। – mafso

उत्तर

10

सी ++ 11 मानक का कहना है:

5,17/1: असाइनमेंट ऑपरेटर (=) और मिश्रित असाइनमेंट ऑपरेटर सभी समूह सही-से-बाएँ। (...) असाइनमेंट दाएं और बाएं ऑपरेटरों की मान गणना के बाद अनुक्रमित है, और असाइनमेंट अभिव्यक्ति की मान गणना से पहले।

1,9/15: एक अदिश वस्तु पर एक पक्ष प्रभाव एक ही अदिश वस्तु या एक मूल्य गणना एक ही अदिश वस्तु के मूल्य का उपयोग करने पर या तो एक और पक्ष प्रभाव को unsequenced रिश्तेदार है, तो व्यवहार अपरिभाषित है ।

  1. *a और *b गणना कर रहे हैं: इस प्रकार

तो *a ^= *b अनुक्रम है। यह नहीं निर्धारित जो क्रम में

  • XOR आपरेशन
  • किया जाता है काम किया जाता है, यानी नया मान *a
  • में संग्रहित है नया मान अभिव्यक्ति के परिणाम के रूप में प्रयोग किया जाता है (*a ^= *b)
  • अब *b ^= *a ^= *b, जो प्राथमिकता नियम के अनुसार *b ^= (*a ^= *b) है:

    1. *b और (*a ^= *b) की गणना की जाती है। यह किस क्रम में निर्धारित है। लेकिन *b(*a ^= *b) द्वारा संशोधित नहीं किया गया है, इससे कोई फर्क नहीं पड़ता।
    2. XOR आपरेशन
    3. काम किया जाता है, यानी नया मान *a ^= *b ^= *a ^= *b साथ अनिर्दिष्ट अनुक्रमण को *b

    में संग्रहित है लेकिन अब जो प्राथमिकता नियमों *a ^= (*b ^= (*a ^= *b)) के अनुसार है किया जाता है:

    1. *a और (*b ^= (*a ^= *b)) की गणना की जाती है। यह किस क्रम में निर्धारित है। लेकिन *a के रूप में (*b ^= (*a ^= *b)) द्वारा संशोधित किया गया है। तो परिणाम इस बात पर निर्भर करेगा कि किस मूल्य की गणना पहले की जाती है। यह स्पष्ट रूप से एक यूबी है।

    मान लीजिए *a पहले मूल्यांकन किया जाता है, (यानी पहले कुछ और):
    आप जो (*b ^= (*a ^= *b)) के मूल्य के साथ xored किया जाएगा इसके बारे में मूल मान, मिलेगा, जो कि मूल *b है मूल के साथ xored *a*b के साथ फिर से xored। इसके परिणामस्वरूप 0 (जिसे *a में संग्रहीत किया जाएगा)।

    मान लीजिए (*b ^= (*a ^= *b)) मूल्यांकन किया जाता है पहले, तो उसके परिणाम मूल *a है, लेकिन *a की सामग्री के मूल *a मूल *b साथ xored करने के लिए बदल गया है। इस प्रकार इस मूल *b (जो *a में संग्रहीत किया जाएगा)

    वैसे में परिणाम होगा, दोनों ही मामलों में, *b*a के मूल मूल्य *b अर्थ है कि *b मूल *a शामिल होंगे साथ दो बार xored शामिल हैं।

    निष्कर्ष: यहाँ प्रदर्शित किया गया है कि *b के अंतिम मूल्य विशिष्ट इस अभिव्यक्ति से निर्धारित होता है, लेकिन वह *a के अंतिम मूल्य विशिष्ट परिभाषित नहीं है (दो मानों संभव हो)। तो यह स्पष्ट रूप से अनसुलझा/संशोधित परिणाम है! यह आपके कंपाइलर के आधार पर स्वैप हो सकता है या *a खो सकता है।

    सुनिश्चित करने के लिए स्वैपिंग कैसे करें?

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

    5,18/1: यह एक अल्पविराम ऑपरेटर द्वारा गारंटी दी जा सकती अल्पविराम से अलग भाव की एक जोड़ी मूल्यांकन किया जाता है बाएँ-से-दाएँ और बाएँ अभिव्यक्ति के मूल्य

    त्याग दिया जाता है

    इसलिए, निम्नलिखित काम करेगा:

    void safe_swap(int* a, int* b) { 
        if (a != b) 
         *b ^= *a ^= *b, *a ^= *b; 
    } 
    
    +0

    यदि आप सही थे कि '* ए' के लिए बिल्कुल दो मान संभव हैं, तो यह अनिर्धारित व्यवहार नहीं होगा, जो कि सबसे खराब नहीं होगा। सी और सी ++ मानकों के अधिकांश संस्करणों में, व्यवहार वास्तव में अपरिभाषित होता है, जिसका अर्थ यह नहीं है कि * कोई * मान वैध है, इसका भी अर्थ है * नहीं * मान वैध है (उदाहरण के लिए प्रोग्राम क्रैश)। लेकिन आप वास्तव में एक दिलचस्प बिंदु उठाते हैं कि भले ही व्यवहार परिभाषित किया गया हो, तो मूल्य को होने की आवश्यकता नहीं है। – hvd

    +0

    @hvd आप शब्दावली के बारे में सही हैं: 5/4 में यह कहा गया है कि अपरिभाषित व्यवहार तब होता है जब "परिणाम गणितीय रूप से परिभाषित नहीं होता है या इसके प्रकार के लिए प्रतिनिधित्व योग्य मानों की सीमा में नहीं होता है"। क्षमा करें अगर मैं गणितीय अर्थ में "अपरिभाषित" का उपयोग करना चाहता हूं। मैं इसे – Christophe

    +0

    सही कर दूंगा "अनसुलझा/संशोधित परिणाम" जैसी कोई चीज़ नहीं है। या तो यह अपरिभाषित व्यवहार है, या यह अनिर्दिष्ट व्यवहार है। –

    संबंधित मुद्दे