क्यों x = x ++ अपरिभाषित है?


19

यह अपरिभाषित है क्योंकि यह xअनुक्रम बिंदुओं के बीच दो बार संशोधित करता है । मानक कहते हैं कि यह अपरिभाषित है, इसलिए यह अपरिभाषित है।
इतना मैं जानता हूं।

लेकिन क्यों?

मेरी समझ यह है कि यह मना करने से कंपाइलर बेहतर अनुकूलन कर सकते हैं। सी का आविष्कार होने पर यह समझ में आ सकता था, लेकिन अब एक कमजोर तर्क की तरह लगता है।
यदि हम आज C को पुष्ट करने के लिए थे, तो क्या हम इसे इस तरह से करेंगे, या इसे बेहतर किया जा सकता है?
या हो सकता है कि एक गहरी समस्या है, जो इस तरह के भावों के लिए लगातार नियमों को परिभाषित करना कठिन बनाता है, इसलिए उन्हें मना करना सबसे अच्छा है?

तो मान लीजिए कि हम आज सी को फिर से मजबूत करने के लिए थे। मैं इस तरह के भावों के लिए सरल नियमों का सुझाव देना चाहता हूं x=x++, जो मुझे मौजूदा नियमों से बेहतर काम करने के लिए लगता है।
मैं मौजूदा लोगों या अन्य सुझावों की तुलना में सुझाए गए नियमों पर आपकी राय लेना चाहता हूं।

सुझाए गए नियम:

  1. अनुक्रम बिंदुओं के बीच, मूल्यांकन का क्रम अनिर्दिष्ट है।
  2. साइड इफेक्ट तुरंत होते हैं।

इसमें कोई अपरिभाषित व्यवहार शामिल नहीं है। अभिव्यक्तियाँ इस मान या उस का मूल्यांकन करती हैं, लेकिन निश्चित रूप से आपकी हार्ड डिस्क को प्रारूपित नहीं करेंगी (अजीब बात है, मैंने कभी ऐसा कार्यान्वयन नहीं देखा है जहाँ x=x++हार्ड डिस्क को प्रारूपित किया जाता है)।

उदाहरण अभिव्यक्तियाँ

  1. x=x++- अच्छी तरह से परिभाषित, नहीं बदलता है x
    सबसे पहले, xबढ़ा हुआ है (तुरंत जब x++मूल्यांकन किया जाता है), तो यह पुराना मूल्य में संग्रहीत होता है x

  2. x++ + ++x- xदो बार वृद्धि , का मूल्यांकन करता है 2*x+2
    हालाँकि दोनों ओर से पहले मूल्यांकन किया जा सकता है, परिणाम या तो x + (x+2)(बाईं ओर पहले) या (x+1) + (x+1)(दाईं ओर पहले) है।

  3. x = x + (x=3)- अनिर्दिष्ट, या xतो करने के लिए सेट । यदि सही पक्ष का मूल्यांकन पहले किया जाता है, तो । यह भी संभव है कि पहले मूल्यांकन किया जाए, इसलिए यह । या तो मामले में, असाइनमेंट का मूल्यांकन होने पर तुरंत होता है, इसलिए संग्रहीत मूल्य को अन्य असाइनमेंट द्वारा अधिलेखित किया जाता है।x+36
    x+3x=33+3x=3x=3

  4. x+=(x=3)- अच्छी तरह से परिभाषित, x6 से सेट।
    आप तर्क कर सकते हैं कि यह ऊपर की अभिव्यक्ति के लिए सिर्फ शॉर्टहैंड है।
    लेकिन मैं कहूंगा कि इसके +=बाद निष्पादित होना चाहिए x=3, और दो भागों में नहीं (पढ़ें x, मूल्यांकन x=3, जोड़ें और स्टोर करें नया मूल्य)।

क्या है फायदा?

कुछ टिप्पणियों ने यह अच्छा मुद्दा उठाया।
मैं निश्चित रूप से ऐसे भाव नहीं सोचता, जैसे x=x++किसी सामान्य कोड में इस्तेमाल किए जाएं।
वास्तव में, मैं इससे कहीं ज्यादा सख्त हूं - मुझे लगता x++है कि x++;अकेले के रूप में एकमात्र अच्छा उपयोग है ।

हालाँकि, मुझे लगता है कि भाषा के नियम यथासंभव सरल होने चाहिए। अन्यथा प्रोग्रामर सिर्फ उन्हें समझ नहीं पाते हैं। नियम को अनुक्रम बिंदुओं के बीच दो बार एक चर को बदलने से मना करना निश्चित रूप से एक नियम है जिसे अधिकांश प्रोग्रामर समझ नहीं पाते हैं।

एक बहुत ही बुनियादी नियम यह है:
यदि A वैध है, और B वैध है, और वे एक वैध तरीके से संयुक्त हैं, तो परिणाम मान्य है।
xएक वैध एल-मूल्य है, x++एक वैध अभिव्यक्ति है, और =एल-मूल्य और एक अभिव्यक्ति को संयोजित करने का एक वैध तरीका है, तो कैसे x=x++कानूनी नहीं है?
सी मानक यहां अपवाद बनाता है, और यह अपवाद नियमों को जटिल बनाता है। आप stackoverflow.com पर खोज कर सकते हैं और देख सकते हैं कि यह अपवाद लोगों को कितना भ्रमित करता है।
तो मैं कहता हूं - इस भ्रम से छुटकारा पाओ।

=== उत्तर का सारांश ===

  1. ऐसा क्यों करते हैं?
    मैंने ऊपर अनुभाग में समझाने की कोशिश की - मैं चाहता हूं कि सी नियम सरल हों।

  2. अनुकूलन के लिए संभावित:
    यह संकलक से कुछ स्वतंत्रता लेता है, लेकिन मैंने ऐसा कुछ भी नहीं देखा जो मुझे आश्वस्त करता हो कि यह महत्वपूर्ण हो सकता है।
    अधिकांश अनुकूलन अभी भी किए जा सकते हैं। उदाहरण के लिए, a=3;b=5;मानक के आदेश को निर्दिष्ट करते हुए भी, फिर से व्यवस्थित किया जा सकता है। अभिव्यक्ति जैसे कि a=b[i++]अभी भी इसी तरह से अनुकूलित किया जा सकता है।

  3. आप मौजूदा मानक को नहीं बदल सकते।
    मैं मानता हूँ, मैं नहीं कर सकता। मैंने कभी नहीं सोचा था कि मैं वास्तव में आगे बढ़ सकता हूं और मानकों और संकलक बदल सकता हूं। मैं केवल यह सोचना चाहता था कि क्या चीजें अलग तरीके से हो सकती हैं।


10
यह आपके लिए क्यों महत्वपूर्ण है? क्या इसे परिभाषित किया जाना चाहिए , और यदि हां, तो क्यों? xअपने आप को असाइन करने के लिए बहुत अधिक बिंदु नहीं है, और यदि आप वेतन वृद्धि चाहते हैं तो आप xकेवल कह सकते हैं x++;- असाइनमेंट की कोई आवश्यकता नहीं है। मैं कहूंगा कि इसे सिर्फ इसलिए परिभाषित नहीं किया जाना चाहिए क्योंकि यह याद रखना मुश्किल होगा कि क्या होने वाला है।
कालेब

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

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

3
मुझे एक और दिलचस्प सवाल यह लगता है कि यह लिखने के लिए कोई त्रुटि क्यों नहीं है? निश्चित रूप से एक कंपाइलर यह अपरिभाषित व्यवहार का पता लगा सकता है और इसलिए संभवतः वह नहीं हो सकता जो उपयोगकर्ता वास्तव में चाहते थे, इसलिए एक त्रुटि में क्यों नहीं है? मैं पता लगाने के लिए अपरिभाषित bahavour कठिन हैं के कुछ उदाहरणों लेकिन इस isn को समझने टी
JohnB

3
" नियम अनुक्रम बिंदुओं के बीच दो बार एक चर को बदलने से मना करना निश्चित रूप से एक नियम है जिसे अधिकांश प्रोग्रामर समझ नहीं पाते हैं। " - क्या आपके पास इसके लिए कोई सबूत है? अधिकांश प्रश्न मैंने देखे हैं क्योंकि प्रोग्रामर नियम के बारे में नहीं जानते थे। क्या कोई सबूत है कि उनमें से अधिकांश को समझाए जाने के बाद भी यह समझ में नहीं आया ?
सिक्योर

जवाबों:


24

हो सकता है कि आपको पहले सवाल का जवाब देना चाहिए कि इसे क्यों परिभाषित किया जाना चाहिए? क्या अतिरिक्त साइड इफेक्ट्स के साथ इस तरह की अभिव्यक्ति की अनुमति देकर प्रोग्रामिंग शैली, पठनीयता, स्थिरता या प्रदर्शन में कोई फायदा है? है

y = x++ + ++x;

से अधिक पठनीय है

y = 2*x + 2;
x += 2;

यह देखते हुए कि इस तरह का बदलाव बेहद मौलिक है और मौजूदा कोड आधार को तोड़ रहा है।


1
मैंने अपने प्रश्न में "क्यों" खंड जोड़ा। मैं निश्चित रूप से इन अभिव्यक्तियों का उपयोग करने का सुझाव नहीं देता, लेकिन मुझे अभिव्यक्ति के अर्थ को बताने के लिए सरल नियम होने में दिलचस्पी है।
ugoren

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

3
खैर, एक और दार्शनिक जवाब: यह वर्तमान में अपरिभाषित है। यदि कोई प्रोग्रामर इसका उपयोग नहीं करता है, तो आपको ऐसे भावों को समझने की कोई आवश्यकता नहीं है, क्योंकि कोई कोड नहीं होना चाहिए। अगर आपको उन्हें समझने की आवश्यकता है, तो जाहिर है कि वहाँ बहुत सारे कोड होने चाहिए जो कि अपरिभाषित व्यवहार पर निर्भर करते हैं। ;)
सुरक्षित

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

1
@ यूगोरेन: आपका "क्यों" खंड अभी भी व्यावहारिक प्रश्न का उत्तर नहीं देता है: आप अपने कोड में इस अजीब अभिव्यक्ति क्यों चाहते हैं? यदि आप उस पर एक ठोस जवाब नहीं दे सकते हैं, तो पूरी चर्चा मूट है।
माइक बैरनज़क

20

यह तर्क कि इस अपरिभाषित व्यवहार को बेहतर अनुकूलन की अनुमति देता है आज कमजोर नहीं है। वास्तव में, यह आज की तुलना में बहुत मजबूत था जब सी नई थी।

जब सी नई थी, तो बेहतर अनुकूलन के लिए इसका लाभ उठाने वाली मशीनें ज्यादातर सैद्धांतिक मॉडल थीं। लोगों ने सीपीयू के निर्माण की संभावना के बारे में बात की थी, जहां कंपाइलर सीपीयू को निर्देश देगा कि अन्य निर्देशों के साथ किन निर्देशों को समानांतर में क्रियान्वित किया जा सकता है। उन्होंने इस तथ्य की ओर इशारा किया कि इसे अपरिभाषित व्यवहार की अनुमति देने का मतलब था कि इस तरह के सीपीयू पर, यदि यह वास्तव में कभी मौजूद था, तो आप अनुदेश के "वृद्धि" हिस्से को बाकी अनुदेश धारा के साथ समानांतर में निष्पादित कर सकते हैं। जब वे सिद्धांत के बारे में सही थे, उस समय हार्डवेयर के रास्ते में बहुत कम था जो वास्तव में इस संभावना का लाभ उठा सकते थे।

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

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

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

C ने जो किया है वह एक अर्ध-उचित दूसरा सबसे अच्छा विकल्प है: लोगों को ऐसा न करने के लिए कहें, जिससे कोड को अस्वीकार करने के लिए कंपाइलर को अनुमति न हो (लेकिन इसकी आवश्यकता नहीं है)। यह उन लोगों के लिए (अभी भी आगे) धीमा संकलन का उपयोग करता है जो कभी भी इसका उपयोग नहीं करेंगे, लेकिन फिर भी किसी को एक कंपाइलर लिखने की अनुमति देता है जो ऐसे कोड को अस्वीकार कर देगा यदि वे चाहते हैं (और / या झंडे हैं जो इसे अस्वीकार कर देंगे जिसे लोग उपयोग करना चुन सकते हैं या नहीं के रूप में वे फिट देखें)।

कम से कम IMO, इस परिभाषित व्यवहार को बनाने के लिए सबसे कम संभव निर्णय होगा (कम से कम करीब) । वीएलआईडब्लू-स्टाइल हार्डवेयर पर, आपको पसंद होगा कि आप इन्क्रीमेंट ऑपरेटरों के उचित उपयोगों के लिए धीमी कोड तैयार करें, केवल भद्दे कोड के लिए जो उन्हें गाली देते हैं, या फिर हमेशा साबित करने के लिए व्यापक प्रवाह विश्लेषण की आवश्यकता होती है, जिससे आप निपट नहीं रहे हैं गंदे कोड, इसलिए आप धीमे (क्रमबद्ध) कोड का उत्पादन तभी कर सकते हैं जब वास्तव में आवश्यक हो।

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


IMO, यह मानने का कोई कारण नहीं है कि ज्यादातर मामलों में, धीमे निर्देश वास्तव में तेज निर्देशों की तुलना में बहुत धीमे हैं और ये हमेशा कार्यक्रम के प्रदर्शन पर प्रभाव डालेंगे। मैं इसे समय से पहले अनुकूलन के तहत वर्गीकृत करूंगा।
डेडएमजी

शायद मुझे कुछ याद आ रहा है - अगर किसी को कभी भी इस तरह के कोड को लिखने की आवश्यकता नहीं है, तो इसे अनुकूलित करने की परवाह क्यों करें?
बदसूरत

1
@ यूगोरेन: a=b[i++];( जैसे एक उदाहरण के लिए) कोड लिखना ठीक है, और इसे अनुकूलित करना एक अच्छी बात है। हालाँकि, मैं उचित कोड को चोट पहुँचाने के बिंदु को उस तरह से नहीं देखता हूँ जैसे कि कुछ ऐसा है ++i++जिसका एक परिभाषित अर्थ है।
जेरी कॉफिन

2
@ यूगोरेन समस्या निदान में से एक है। इस तरह के रूप ++i++में स्पष्ट रूप से अव्यवस्थित अभिव्यक्ति नहीं करने का एकमात्र उद्देश्य यह है कि उन्हें साइड-इफेक्ट्स (जैसे a=b[i++]) के साथ वैध अभिव्यक्तियों से अलग करना सामान्य रूप से कठिन है । यह हमारे लिए काफी सरल लग सकता है, अगर मुझे ड्रैगन बुक सही ढंग से याद है तो यह वास्तव में एक एनपी-कठिन समस्या है। ऐसा इसलिए है क्यों इस व्यवहार, यूबी है मना करने के बजाय।
कोनराड रुडोल्फ

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

9

एरिक लिपर्ट, सी # कंपाइलर टीम के एक प्रमुख डिजाइनर, ने अपने ब्लॉग पर कई तरह के विचारों के बारे में एक लेख पोस्ट किया है , जो भाषा के विशेष स्तर पर एक सुविधा को अपरिभाषित बनाने के लिए चुनने में जाते हैं। जाहिर है C # एक अलग भाषा है, जिसके विभिन्न कारक इसकी भाषा डिजाइन में जाते हैं, लेकिन वह जो बिंदु बनाता है वह प्रासंगिक है।

विशेष रूप से, वह उस भाषा के लिए मौजूदा संकलक होने के मुद्दे को इंगित करता है जिसमें मौजूदा कार्यान्वयन हैं और एक समिति में प्रतिनिधि भी हैं। मुझे यकीन नहीं है कि अगर यहां मामला है, लेकिन ज्यादातर सी और सी ++ संबंधित कल्पना चर्चा के लिए प्रासंगिक है।

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


आपके द्वारा लिंक किए गए लेख से, ऐसा लगता है जैसे मैं जो सुझाव देता हूं, वह C # से दूर नहीं है। साइड इफेक्ट्स के ऑर्डर को परिभाषित किया जाता है "जब थ्रेड से मनाया जाता है जो साइड इफेक्ट का कारण बनता है"। मैंने मल्टी-थ्रेडिंग का उल्लेख नहीं किया है, लेकिन सामान्य तौर पर सी किसी अन्य थ्रेड में एक पर्यवेक्षक के लिए बहुत गारंटी नहीं देता है।
बदसूरत

5

पहले, आइए अपरिभाषित व्यवहार की परिभाषा पर एक नज़र डालें :

3.4.3

1 unde behavior
ned व्यवहार व्यवहार, किसी गैर-योग्य या त्रुटिपूर्ण प्रोग्राम के निर्माण या गलत डेटा के उपयोग पर, जिसके लिए यह अंतर्राष्ट्रीय मानक कोई आवश्यकता नहीं लगाता है

2 नोट संभव unde behavior ned व्यवहार में अप्रत्याशित परिणामों की अनदेखी करने से लेकर अनुवाद या प्रोग्राम निष्पादन के दौरान व्यवहार करना शामिल है। पर्यावरण (एक नैदानिक ​​संदेश जारी करने के साथ या बिना) की एक दस्तावेज तरीके से विशेषता, एक अनुवाद या निष्पादन (एक नैदानिक ​​संदेश जारी करने के साथ) को समाप्त करने के लिए।

3 उदाहरण AMP ned व्यवहार का एक उदाहरण। Ow पर पूर्णांक पर व्यवहार है

तो दूसरे शब्दों में, "अपरिभाषित व्यवहार" का सीधा मतलब है कि संकलक किसी भी तरह से स्थिति को संभालने के लिए स्वतंत्र है और इस तरह की किसी भी कार्रवाई को "सही" माना जाता है।

चर्चा के अंतर्गत समस्या की जड़ निम्न खंड है:

६.५ भाव

...
3 ऑपरेटरों और ऑपरेंडों के समूह को सिंटैक्स द्वारा दर्शाया गया है। 74) को छोड़कर विशिष्ट बाद में (एड समारोह-कॉल के लिए (), &&, ||, ?:, और अल्पविराम ऑपरेटर), subexpressions के मूल्यांकन के आदेश और जिस क्रम में साइड इफेक्ट जगह ले दोनों unspeci फाई एड कर रहे हैं

महत्व दिया।

जैसी अभिव्यक्ति दी

x = a++ * --b / (c + ++d);

subexpressions a++, --b, c, और ++dमूल्यांकन किया जा सकता किसी भी क्रम में । इसके अलावा, के साइड इफेक्ट a++, --bऔर ++dकिसी भी बिंदु पर अगले अनुक्रम बिंदु से पहले लागू किया जा सकता (IOW, भले ही a++पहले मूल्यांकन किया जाता है --b, यह गारंटी नहीं है कि aहो जाएगा अद्यतन से पहले --bमूल्यांकन किया जाता है)। जैसा कि अन्य लोगों ने कहा है, इस व्यवहार के लिए तर्क कार्यान्वयन को एक इष्टतम तरीके से संचालन को स्वतंत्रता देने के लिए है।

इस वजह से, हालांकि, जैसे भाव

x = x++
y = i++ * i++
a[i] = i++
*p++ = -*p    // this one bit me just yesterday

आदि, अलग-अलग कार्यान्वयन के लिए अलग-अलग परिणाम देगा (या अलग-अलग अनुकूलन सेटिंग्स के साथ एक ही कार्यान्वयन के लिए, या आसपास के कोड के आधार पर, आदि)।

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

जाहिर है, आप ऐसी भाषा डिज़ाइन कर सकते हैं जो मूल्यांकन के क्रम और जिस क्रम में साइड इफेक्ट्स लागू होते हैं, उसे सख्ती से परिभाषित किया गया हो, और जावा और सी # दोनों ऐसा करते हैं, मोटे तौर पर उन मुद्दों से बचने के लिए जो सी और सी ++ परिभाषाओं का नेतृत्व करते हैं।

तो, 3 मानक संशोधनों के बाद C में यह परिवर्तन क्यों नहीं किया गया है? सबसे पहले, वहाँ विरासत कोड कोड के 40 साल के लायक है, और यह गारंटी नहीं है कि इस तरह के परिवर्तन से उस कोड को नहीं तोड़ा जाएगा। यह संकलक लेखकों पर थोड़ा बोझ डालता है, क्योंकि इस तरह के बदलाव से सभी मौजूदा संकलक गैर-अनुरूप हो जाएंगे; हर किसी को महत्वपूर्ण लेखन करना होगा। और तेज, आधुनिक सीपीयू पर भी, मूल्यांकन के क्रम को बदलकर वास्तविक प्रदर्शन लाभ का एहसास करना संभव है।


1
मुद्दे की बहुत अच्छी व्याख्या। मैं विरासत अनुप्रयोगों को तोड़ने के बारे में असहमत हूं - जिस तरह से अपरिभाषित / अनिर्दिष्ट व्यवहार को लागू किया जाता है वह कभी-कभी कंपाइलर संस्करण के बीच परिवर्तन होता है, बिना किसी मानक के परिवर्तन के। मैं किसी भी परिभाषित व्यवहार को बदलने का सुझाव नहीं देता।
बदसूरत

4

पहले आपको यह समझना होगा कि यह सिर्फ x = x ++ नहीं है जो अपरिभाषित है। कोई भी एक्स = एक्स ++ के बारे में परवाह नहीं करता है, क्योंकि इससे कोई फर्क नहीं पड़ता कि आप इसे परिभाषित करेंगे कि इसका कोई मतलब नहीं है। अपरिभाषित क्या अधिक है जैसे "a = b ++ जहां a और b एक ही होते हैं" - यानी

void f(int *a, int *b) {
    *a = (*b)++;
}
int i;
f(&i, &i);

प्रोसेसर आर्किटेक्चर के लिए (और आसपास के बयानों के लिए, यह उदाहरण से अधिक जटिल कार्य है) के लिए सबसे अधिक कुशल होने के आधार पर फ़ंक्शन के कई अलग-अलग तरीके हो सकते हैं। उदाहरण के लिए, दो स्पष्ट:

load r1 = *b
copy r2 = r1
increment r1
store *b = r1
store *a = r2

या

load r1 = *b
store *a = r1
increment r1
store *b = r1

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


आप वास्तव में एक मामला दिखाते हैं, जहां मेरे सुझाव से मशीन के संचालन में अधिक परिणाम होते हैं, लेकिन यह मेरे लिए महत्वहीन है। और संकलक के पास अभी भी कुछ स्वतंत्रता है - जो एकमात्र वास्तविक आवश्यकता मैं जोड़ रहा हूं वह bपहले स्टोर करना है a
6

3

विरासत

C को पुनर्निमित किया जा सकने वाली धारणा आज धारण नहीं कर सकती है। सी कोड्स की इतनी सारी पंक्तियाँ हैं जिनका उत्पादन और दैनिक उपयोग किया जाता है, कि खेल के नियमों को खेल के बीच में बदलना सिर्फ गलत है।

बेशक आप एक नई भाषा का आविष्कार कर सकते हैं, अपने नियमों के साथ C + = कह सकते हैं। लेकिन वह C नहीं होगा।


2
मुझे नहीं लगता कि हम आज सी को फिर से स्थापित कर सकते हैं। इसका मतलब यह नहीं है कि हम इन मुद्दों पर चर्चा नहीं कर सकते। हालाँकि, मेरा सुझाव है कि वास्तव में पुनर्निवेश नहीं है। परिभाषित या अनिर्दिष्ट व्यवहार के लिए अपरिभाषित व्यवहार को परिवर्तित करना एक मानक को अद्यतन करते समय किया जा सकता है, और भाषा अभी भी C.
बदसूरत

2

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

धारणा के लिए मुख्य मुद्दा यह नहीं है x = x++;(संकलक आसानी से इसके लिए जांच कर सकते हैं और चेतावनी देनी चाहिए), यह है *p1 = (*p2)++और समकक्ष ( p1[i] = p2[j]++;जब p1 और p2 एक फ़ंक्शन के पैरामीटर हैं) जहां संकलक आसानी से पता नहीं कर सकता है यदि p1 == p2(C99 में) restrictअनुक्रम बिंदुओं के बीच p1! = P2 ग्रहण करने की संभावना को फैलाने के लिए जोड़ा गया है, इसलिए यह समझा गया कि अनुकूलन संभावनाएं महत्वपूर्ण थीं)।


मैं यह नहीं देखता कि मेरा सुझाव किस संबंध में कुछ भी बदलता है p1[i]=p2[j]++। यदि कंपाइलर अलियासिंग नहीं मान सकता है, तो कोई समस्या नहीं है। यदि यह नहीं हो सकता है, तो यह पुस्तक द्वारा जाना चाहिए - वेतन वृद्धि p2[j]पहले, p1[i]बाद में स्टोर करें । खोए हुए अनुकूलन अवसरों को छोड़कर, जो महत्वपूर्ण नहीं लगते हैं, मुझे कोई समस्या नहीं दिखती है।
ugoren

दूसरा पैराग्राफ पहले से स्वतंत्र नहीं था, लेकिन इस तरह के स्थानों का एक उदाहरण जहां धारणा में कमी हो सकती है और ट्रैक करना मुश्किल होगा।
एपीग्रामग्राम

पहला पैराग्राफ कुछ स्पष्ट बताता है - नए मानक के अनुपालन के लिए संकलक को बदलना होगा। मुझे नहीं लगता कि मेरे पास इसे मानकीकृत करने और संकलक लेखकों का अनुसरण करने का मौका है। मुझे लगता है कि यह चर्चा के लायक है।
बदसूरत

समस्या यह नहीं है कि भाषा में किसी भी बदलाव के बारे में संकलक को बदलने की जरूरत है, यह है कि परिवर्तन व्यापक हैं और खोजने के लिए कठिन जगह पर हैं। सबसे अधिक व्यावहारिक दृष्टिकोण शायद मध्यवर्ती प्रारूप में बदलाव किया जाएगा, जिस पर अनुकूलक काम करता है, यानी कि नाटक x = x++;नहीं लिखा गया, लेकिन t = x; x++; x = t;या x=x; x++;या जो भी आप अर्थ के रूप में चाहते हैं (लेकिन निदान के बारे में क्या?)। एक नई भाषा के लिए, बस साइड इफेक्ट को छोड़ दें।
एपीग्रामग्राम

मैं संकलक संरचना के बारे में बहुत अधिक नहीं जानता। अगर मैं वास्तव में सभी संकलक बदलना चाहता था, तो मैं और अधिक परवाह करूंगा। लेकिन शायद x++एक अनुक्रम बिंदु के रूप में व्यवहार कर रहा था, जैसे कि यह एक फ़ंक्शन कॉल था inc_and_return_old(&x)
ugoren

-1

कुछ मामलों में, इस तरह के कोड को नए C ++ 11 मानक में परिभाषित किया गया था


5
विस्तृत करने के लिए परवाह?
ugoren

मुझे लगता x = ++xहै कि अब अच्छी तरह से परिभाषित (लेकिन नहीं x = x++) है
एमएम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.