व्यवहार में, अलग-अलग कंपाइलर इंट x = ++ i + ++ i के विभिन्न मूल्यों की गणना क्यों करते हैं ?;


165

इस कोड पर विचार करें:

int i = 1;
int x = ++i + ++i;

हमारे पास इस कोड के लिए एक संकलक क्या कर सकता है, इसके लिए कुछ अनुमान है, यह मानकर कि यह संकलित है।

  1. दोनों ++iलौटते हैं 2, जिसके परिणामस्वरूप x=4
  2. एक ++iरिटर्न 2और दूसरा रिटर्न 3, जिसके परिणामस्वरूप x=5
  3. दोनों ++iलौटते हैं 3, जिसके परिणामस्वरूप x=6

मेरे लिए, दूसरा सबसे अधिक संभावना है। दो ++ऑपरेटरों में से एक के साथ निष्पादित होता है i = 1, iवेतन वृद्धि होती है, और परिणाम 2वापस आ जाता है। फिर दूसरे ++ऑपरेटर के साथ निष्पादित किया जाता है i = 2, iवेतन वृद्धि की जाती है, और परिणाम 3वापस किया जाता है। तब 2और 3देने के लिए एक साथ जोड़ दिए जाते हैं 5

हालाँकि, मैंने इस कोड को Visual Studio में चलाया, और परिणाम यह रहा 6। मैं संकलकों को बेहतर ढंग से समझने की कोशिश कर रहा हूं, और मैं सोच रहा हूं कि इसके परिणामस्वरूप क्या हो सकता है 6। मेरा एकमात्र अनुमान है कि कोड को कुछ "बिल्ट-इन" संगामिति के साथ निष्पादित किया जा सकता है। दो ++ऑपरेटरों को बुलाया गया था, प्रत्येक iने दूसरे के लौटने से पहले वेतन वृद्धि की और फिर वे दोनों वापस आ गए 3। यह कॉल स्टैक की मेरी समझ का खंडन करेगा, और इसे दूर करने की आवश्यकता होगी।

क्या (वाजिब) चीजें एक C++संकलक कर सकती हैं जो परिणाम 4या परिणाम के लिए नेतृत्व करेगी 6?

ध्यान दें

यह उदाहरण Bjarne Stroustrup के प्रोग्रामिंग में अपरिभाषित व्यवहार के उदाहरण के रूप में प्रकट हुआ: C ++ (C ++ 14) का उपयोग करते हुए सिद्धांत और अभ्यास।

दालचीनी की टिप्पणी देखें ।


5
सी कल्पना वास्तव में केवल बाईं ओर पूर्व / उत्तर-संचालन कार्यों की तुलना में = के दाईं ओर संचालन या मूल्यांकन के आदेश को कवर नहीं करती है।
क्रिस्टोबोल पॉलीक्रोनोपोलिस

2
अनुशंसा करें कि आप प्रश्न में प्रशस्ति पत्र देते हैं यदि आपको यह उदाहरण स्ट्रॉस्ट्रुप की एक पुस्तक से मिला है (जैसा कि किसी एक उत्तर में टिप्पणी में वर्णित है)।
डैनियल आर। कॉलिन्स

4
@philipxy आपके सुझाए गए डुप्लिकेट इस प्रश्न का डुप्लिकेट नहीं है। सवाल अलग हैं। आपके सुझाए गए डुप्लिकेट के उत्तर इस प्रश्न का उत्तर नहीं देते हैं। आपके सुझाए गए डुप्लिकेट के उत्तर इस प्रश्न के लिए स्वीकृत (या उच्च मत) उत्तर (ओं) के डुप्लिकेट नहीं हैं। मेरा मानना ​​है कि आपने मेरे सवाल को गलत बताया है। मेरा सुझाव है कि आप इसे फिर से पढ़ें और वोट को फिर से बंद करने पर पुनर्विचार करें।
दालचीनी

3
@philipxy "उत्तर कहते हैं कि एक कंपाइलर कुछ भी कर सकता है ..." जो मेरे प्रश्न का उत्तर नहीं देता है। "वे दिखाते हैं कि भले ही आपको लगता है कि आपका प्रश्न अलग है, यह केवल उस पर भिन्नता है" क्या? "हालांकि आप C ++ का अपना संस्करण नहीं देते हैं" C ++ का मेरा संस्करण मेरे प्रश्न के लिए अप्रासंगिक है। "इसलिए पूरे कार्यक्रम में कथन कुछ भी कर सकता है" मुझे पता है, लेकिन मेरा प्रश्न विशिष्ट व्यवहार के बारे में था। "आपकी टिप्पणी वहाँ जवाब की सामग्री को प्रतिबिंबित नहीं करता है।" मेरी टिप्पणी मेरे प्रश्न की सामग्री को दर्शाती है, जिसे आपको फिर से पढ़ना चाहिए।
दालचीनी

2
शीर्षक का जवाब देने के लिए; क्योंकि UB का अर्थ है कि bahavioir अपरिभाषित है। विभिन्न आर्किटेक्चर के लिए अलग-अलग लोगों द्वारा, इतिहास के दौरान अलग-अलग समय पर किए गए कई कंपाइलर, जब लाइनों के बाहर रंग करने के लिए कहा जाता है और एक वास्तविक विश्व कार्यान्वयन होता है , तो उन्हें विनिर्देश के बाहर इस हिस्से में कुछ डालना पड़ता है, इसलिए लोगों ने बिल्कुल ऐसा किया और प्रत्येक उनमें से विभिन्न crayons का इस्तेमाल किया। इसलिए होरी मैक्सिम,
टोबी

जवाबों:


200

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

कोड

int i = 1;
int x = ++i + ++i;

निम्नलिखित निर्देश शामिल हैं:

1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
5. read i as tmp2
6. read i as tmp3
7. add 1 to tmp3
8. store tmp3 in i
9. read i as tmp4
10. add tmp2 and tmp4, as tmp5
11. store tmp5 in x

लेकिन इस तरह की संख्या सूची में होने के बावजूद मैंने इसे लिखा, यहां केवल कुछ आदेश निर्भरताएं हैं: 1-> 2-> 3-> 4-> 5-> 10-> 11 और 1-> 6-> 7- > 8-> 9-> 10-> 11 को अपने रिश्तेदार क्रम में रहना चाहिए। इसके अलावा संकलक स्वतंत्र रूप से फिर से काम कर सकते हैं, और शायद अतिरेक को खत्म कर सकते हैं।

उदाहरण के लिए, आप सूची को इस तरह से ऑर्डर कर सकते हैं:

1. store 1 in i
2. read i as tmp1
6. read i as tmp3
3. add 1 to tmp1
7. add 1 to tmp3
4. store tmp1 in i
8. store tmp3 in i
5. read i as tmp2
9. read i as tmp4
10. add tmp2 and tmp4, as tmp5
11. store tmp5 in x

संकलक ऐसा क्यों कर सकता है? क्योंकि वेतन वृद्धि के दुष्प्रभावों के लिए कोई अनुक्रमण नहीं है। लेकिन अब कंपाइलर सरल कर सकता है: उदाहरण के लिए, 4 में एक मृत दुकान है: मान तुरंत अधिलेखित कर दिया गया है। इसके अलावा, tmp2 और tmp4 वास्तव में एक ही बात है।

1. store 1 in i
2. read i as tmp1
6. read i as tmp3
3. add 1 to tmp1
7. add 1 to tmp3
8. store tmp3 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x

और अब tmp1 के साथ करने के लिए सब कुछ मृत कोड है: इसका उपयोग कभी नहीं किया जाता है। और मैं फिर से पढ़ा भी समाप्त किया जा सकता है:

1. store 1 in i
6. read i as tmp3
7. add 1 to tmp3
8. store tmp3 in i
10. add tmp3 and tmp3, as tmp5
11. store tmp5 in x

देखो, यह कोड बहुत छोटा है। आशावादी खुश है। प्रोग्रामर नहीं है, क्योंकि मुझे केवल एक बार वेतन वृद्धि दी गई थी। उफ़।

आइए इसके बजाय कंपाइलर कुछ और कर सकता है: आइए मूल संस्करण पर वापस जाते हैं।

1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
5. read i as tmp2
6. read i as tmp3
7. add 1 to tmp3
8. store tmp3 in i
9. read i as tmp4
10. add tmp2 and tmp4, as tmp5
11. store tmp5 in x

संकलक इसे इस तरह से पुन: व्यवस्थित कर सकता है:

1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
6. read i as tmp3
7. add 1 to tmp3
8. store tmp3 in i
5. read i as tmp2
9. read i as tmp4
10. add tmp2 and tmp4, as tmp5
11. store tmp5 in x

और फिर ध्यान दें कि मैं दो बार पढ़ा गया हूं, इसलिए उनमें से एक को समाप्त करें:

1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
6. read i as tmp3
7. add 1 to tmp3
8. store tmp3 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x

यह अच्छा है, लेकिन यह आगे जा सकता है: यह tmp1 का पुन: उपयोग कर सकता है:

1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
6. read i as tmp1
7. add 1 to tmp1
8. store tmp1 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x

तो यह 6 में i के पुनः पढ़ने को समाप्त कर सकता है:

1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
7. add 1 to tmp1
8. store tmp1 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x

अब 4 एक मृत दुकान है:

1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
7. add 1 to tmp1
8. store tmp1 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x

और अब 3 और 7 को एक निर्देश में मिलाया जा सकता है:

1. store 1 in i
2. read i as tmp1
3+7. add 2 to tmp1
8. store tmp1 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x

अंतिम अस्थायी को हटा दें:

1. store 1 in i
2. read i as tmp1
3+7. add 2 to tmp1
8. store tmp1 in i
10. add tmp1 and tmp1, as tmp5
11. store tmp5 in x

और अब आपको वह परिणाम मिलता है जो Visual C ++ आपको दे रहा है।

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


36
वर्तमान में, यह एकमात्र उत्तर है जिसमें अनुक्रमण का उल्लेख है
बजे PM 2Ring

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

3
यह पढ़ा-संशोधित-लेखन कार्य मानता है। कुछ सीपीयू, जैसे कि सर्वव्यापी x86, में एक परमाणु वृद्धि ऑपरेशन होता है, जो स्थिति में और भी अधिक जटिलता जोड़ता है।
मार्क

6
@philipxy "मानक में ऑब्जेक्ट कोड के बारे में कहने के लिए कुछ नहीं है।" मानक के पास इस स्निपेट के व्यवहार के बारे में कहने के लिए कुछ भी नहीं है - यह यूबी है। यह सवाल का एक आधार है। ओपी यह जानना चाहता था कि व्यवहार में, संकलक विभिन्न और अजीब परिणामों पर क्यों आ सकते हैं। इसके अलावा, मेरा जवाब ऑब्जेक्ट कोड के बारे में भी कुछ नहीं कहता है।
सेबस्टियन रेडल

5
@philipxy मैं आपकी आपत्ति को नहीं समझता। जैसा कि उल्लेख किया गया है, सवाल यह है कि एक संकलक यूबी की उपस्थिति में क्या कर सकता है, सी ++ मानक के बारे में नहीं। एक काल्पनिक संकलक कोड को कैसे बदल रहा है, इसकी खोज करते समय ऑब्जेक्ट कोड का उपयोग करना अनुचित क्यों होगा? वास्तव में, वस्तु कोड क्या कुछ भी प्रासंगिक होगा?
कोनराड रुडोल्फ

58

हालांकि यह यूबी है (जैसा कि ओपी ने कहा है), निम्नलिखित काल्पनिक तरीके हैं कि एक कंपाइलर 3 परिणाम प्राप्त कर सकता है। तीनों एक ही सही xपरिणाम देंगे यदि int i = 1, j = 1;एक और एक के बजाय अलग-अलग चर के साथ उपयोग किया जाए i

  1. दोनों ++ मैं 2 लौटाते हैं, जिसके परिणामस्वरूप x = 4 होता है।
int i = 1;
int i1 = i, i2 = i;   // i1 = i2 = 1
++i1;                 // i1 = 2
++i2;                 // i2 = 2
int x = i1 + i2;      // x = 4
  1. एक ++ मैं 2 रिटर्न करता है और दूसरा 3 रिटर्न करता है, जिसके परिणामस्वरूप x = 5 होता है।
int i = 1;
int i1 = ++i;           // i1 = 2
int i2 = ++i;           // i2 = 3
int x = i1 + i2;        // x = 5
  1. दोनों ++ मैं 3 पर लौटते हैं, जिसके परिणामस्वरूप x = 6 है।
int i = 1;
int &i1 = i, &i2 = i;
++i1;                   // i = 2
++i2;                   // i = 3
int x = i1 + i2;        // x = 6

2
यह एक बेहतर प्रतिक्रिया है जो मैंने उम्मीद की थी, धन्यवाद।
दालचीनी

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

@dxiv क्षमा करें, मेरा बुरा, मैंने पदों को मिला दिया
मुरु

22

मेरे लिए, दूसरा सबसे अधिक संभावना है।

मैं विकल्प # 4 के लिए जा रहा हूं: दोनों ++iसमवर्ती रूप से होते हैं।

नए प्रोसेसर कुछ दिलचस्प अनुकूलन और समानांतर कोड मूल्यांकन की ओर बढ़ते हैं, जहां यहां की अनुमति है, एक और तरीका है कि कंपाइलर तेजी से कोड बनाते रहते हैं। मैं एक व्यावहारिक कार्यान्वयन के रूप में देखता हूं , संकलक समानता की ओर बढ़ रहे हैं।

मैं आसानी से एक दौड़ की स्थिति को गैर-नियतात्मक व्यवहार या एक बस दोष के कारण एक ही स्मृति विवाद के कारण देख सकता था - सभी की अनुमति दी क्योंकि कोडर ने सी ++ अनुबंध का उल्लंघन किया - इसलिए यूबी।

मेरा सवाल है: क्या (उचित) चीजें एक सी ++ संकलक कर सकती हैं जो 4 या एक परिणाम या 6 का परिणाम देगा?

यह हो सकता है , लेकिन इसमें गिनती नहीं है।

++i + ++iसमझदार परिणामों का उपयोग न करें और न ही उम्मीद करें ।


अगर मैं इस उत्तर और @ dxiv के दोनों को स्वीकार कर लेता। जवाब देने के लिए धन्यवाद।
दालचीनी

4
@UriRaz: प्रोसेसर को नोटिस भी नहीं हो सकता है कि कंपाइलर की पसंद के आधार पर डेटा खतरा है। जैसे कंपाइलर iदो रजिस्टरों को असाइन कर सकता है , दोनों रजिस्टरों को बढ़ा सकता है , और उन दोनों को वापस लिख सकता है। प्रोसेसर के पास इसे हल करने का कोई तरीका नहीं है। मूलभूत समस्या यह है कि न तो सी ++ और न ही आधुनिक सीपीयू सख्ती से अनुक्रमिक हैं। सी ++ स्पष्ट रूप से होता है-पहले और होता है-सीक्वेंसिंग के बाद, डिफ़ॉल्ट रूप से एक ही समय में होने की अनुमति देने के लिए।
एमएसलटर्स

1
लेकिन हम जानते हैं कि विज़ुअल स्टूडियो का उपयोग करते हुए ओपी के लिए ऐसा नहीं है; x86 और ARM सहित अधिकांश मुख्यधारा ISAs निष्पादन के एक पूरी तरह से अनुक्रमिक मॉडल के संदर्भ में परिभाषित किए गए हैं जहां एक मशीन निर्देश अगले एक शुरू होने से पहले पूरी तरह से खत्म हो जाता है। Superscalar आउट-ऑफ-ऑर्डर को एकल धागे के लिए उस भ्रम को बनाए रखना चाहिए। (साझा मेमोरी पढ़ने वाले अन्य थ्रेड्स को प्रोग्राम ऑर्डर में चीजों को देखने की गारंटी नहीं है, लेकिन ओओओ निष्पादन का कार्डिनल नियम एकल-थ्रेडेड निष्पादन को तोड़ने के लिए नहीं है।)
पीटर कॉर्ड्स

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

1
@AgniusVasiliauskas शायद, अभी तक "व्यवहार में, अलग-अलग संकलक अलग-अलग मूल्यों की गणना क्यों करेंगे" आज के प्रोसेसर के एक सरल दृष्टिकोण को समझने के लिए एक आसान के लिए अधिक लग रही है। अभी तक संकलक / प्रोसेसर परिदृश्यों की श्रेणी यदि उल्लिखित कुछ विभिन्न उत्तरों से कहीं अधिक है। आपकी उपयोगी जानकारी अभी तक एक और है। आईएमओ, समानतावाद भविष्य है और इसलिए यह जवाब उन पर केंद्रित है, यद्यपि एक सार तरीके से - जैसा कि भविष्य अभी भी सामने है। IAC, पोस्ट लोकप्रिय हो गया है और उत्तर समझना आसान है, सर्वश्रेष्ठ पुरस्कृत हैं।
chux -

17

मुझे लगता है कि एक सरल और सीधी व्याख्या (संकलक अनुकूलन या मल्टीथ्रेडिंग के लिए किसी भी बोली के बिना) सिर्फ होगी:

  1. वेतन वृद्धि i
  2. वेतन वृद्धि i
  3. i+ जोड़ेंi

iदो बार वृद्धि के साथ , इसका मूल्य 3 है, और जब एक साथ जोड़ा जाता है, तो योग 6 होता है।

निरीक्षण के लिए, इसे C ++ फ़ंक्शन के रूप में देखें:

int dblInc ()
{
    int i = 1;
    int x = ++i + ++i;
    return x;   
}

अब, यहाँ जीएनयू C ++ कंपाइलर (win32, gcc संस्करण 3.4.2 (mingw-special)) के पुराने संस्करण का उपयोग करके, उस फ़ंक्शन को संकलित करने से मुझे असेंबली कोड मिलता है। यहाँ कोई फैंसी अनुकूलन या मल्टीथ्रेडिंग नहीं हो रहा है:

__Z6dblIncv:
    push    ebp
    mov ebp, esp
    sub esp, 8
    mov DWORD PTR [ebp-4], 1
    lea eax, [ebp-4]
    inc DWORD PTR [eax]
    lea eax, [ebp-4]
    inc DWORD PTR [eax]
    mov eax, DWORD PTR [ebp-4]
    add eax, DWORD PTR [ebp-4]
    mov DWORD PTR [ebp-8], eax
    mov eax, DWORD PTR [ebp-8]
    leave
    ret

ध्यान दें कि स्थानीय चर iकेवल एक ही स्थान पर स्टैक पर बैठा है: पता [ebp-4]। उस स्थान को दो बार (असेंबली फ़ंक्शन की 5 वीं -8 वीं लाइनों में, उस पते के जाहिरा तौर पर निरर्थक भार सहित) बढ़ाया जाता है eax। फिर 9 वीं -10 वीं लाइनों पर, उस मान को लोड किया जाता है eax, और फिर eax(वर्तमान की गणना करता है i + i) में जोड़ा जाता है । फिर इसे अतिरेक से स्टैक पर कॉपी किया eaxजाता है और रिटर्न मान के रूप में (जो स्पष्ट रूप से 6 होगा)।

यह सी ++ मानक (यहां, एक पुराना: आईएसओ / आईईसी 14882: 1998 (ई)) जो अभिव्यक्तियों के लिए कहता है, खंड 5.4 को देखने के लिए रुचि हो सकती है: 5.4

जहां नोट किया गया है, सिवाय इसके कि अलग-अलग संचालकों के संचालनों के मूल्यांकन और अलग-अलग अभिव्यक्तियों के उप-अनुक्रम का क्रम, और जिस क्रम में दुष्प्रभाव होते हैं, वह अनिर्दिष्ट है।

फुटनोट के साथ:

ऑपरेटरों की पूर्वता सीधे निर्दिष्ट नहीं है, लेकिन इसे सिंटैक्स से लिया जा सकता है।

अनिर्दिष्ट व्यवहार के दो उदाहरण उस बिंदु पर दिए गए हैं, जिसमें दोनों वृद्धि ऑपरेटर शामिल हैं (जिनमें से एक है:) i = ++i + 1

अब, यदि कोई चाहे, तो एक पूर्णांक आवरण वर्ग (जैसे जावा इंटेगर) बना सकता है; अधिभार कार्यों operator+और operator++ऐसे कि वे मध्यवर्ती मूल्य की वस्तुओं को वापस करते हैं; और इस प्रकार लिखो ++iObj + ++iObjऔर प्राप्त करो 5. एक वस्तु को वापस लेने के लिए 5. (मैंने संक्षिप्तता के लिए यहां पूर्ण कोड शामिल नहीं किया है।)

व्यक्तिगत रूप से, अगर मैं एक प्रसिद्ध संकलक का एक उदाहरण था, जो ऊपर देखे गए अनुक्रम की तुलना में किसी अन्य तरीके से काम करता है, तो मुझे बहुत मुश्किल होगा। मुझे ऐसा लगता है कि सबसे सीधा कार्यान्वयन यह होगा incकि अतिरिक्त ऑपरेशन किए जाने से पहले सिर्फ दो विधानसभा-कोड एस को आदिम प्रकार पर करना होगा।


2
वृद्धि ऑपरेटर वास्तव
edc65

@philipxy: मैंने उन अंशों को निकालने के लिए उत्तर संपादित किया है, जिन पर आपने आपत्ति जताई थी। आप इस बिंदु पर और अधिक जवाब से सहमत हो सकते हैं या नहीं।
डैनियल आर। कॉलिन्स

2
वे "अनिर्दिष्ट व्यवहार के दो उदाहरण" नहीं हैं, वे अपरिभाषित व्यवहार के दो उदाहरण हैं , एक बहुत ही अलग जानवर, जो मानक में एक अलग मार्ग से उत्पन्न होता है। मैं देखता हूँ कि C ++ 98 का ​​उपयोग फुटनोट के उदाहरण के पाठ में "अनिर्दिष्ट" के रूप में किया गया था, जो कि मानक पाठ के विपरीत है, लेकिन बाद में इसे ठीक कर दिया गया था।
काबुबी

@ कुब्बी: यहां उद्धृत मानक में पाठ और फुटनोट दोनों "अनिर्दिष्ट" वाक्यांश का उपयोग करते हैं, "सीधे निर्दिष्ट नहीं", और यह परिभाषा से खंड 1.3.13 से मेल खाता लगता है।
डैनियल आर। कोलिन्स ने

1
@philipxy: मैं देख रहा हूं कि आपने यहां कई उत्तरों में एक ही टिप्पणी दोहराई है। ऐसा लगता है कि आपकी मुख्य आलोचना वास्तव में ओपी के प्रश्न के बारे में अधिक है, जिसका दायरा केवल अमूर्त मानक के बारे में नहीं है।
डैनियल आर। कोलिन्स ने

7

एक संकलक कर सकते हैं कि उचित बात आम Subexpression उन्मूलन है। यह पहले से ही संकलक में एक सामान्य अनुकूलन है: यदि एक उपप्रकारक जैसे (x+1)बड़े अभिव्यक्ति में एक से अधिक बार होता है, तो इसे केवल एक बार गणना करने की आवश्यकता होती है। में उदाहरण के उप अभिव्यक्ति एक बार गणना की जा सकती।a/(x+1) + b*(x+1)x+1

बेशक, संकलक को यह जानना होगा कि किस तरह से उप-अभिव्यक्तियों को अनुकूलित किया जा सकता है। rand()दो बार कॉल करने पर दो रैंडम नंबर देने चाहिए। अ-इन-फ़ंक्शन फ़ंक्शन कॉल इसलिए CSE से छूट होनी चाहिए। जैसा कि आप ध्यान दें, कोई नियम नहीं है जो कहता है कि दो घटनाओं को कैसे i++नियंत्रित किया जाना चाहिए, इसलिए उन्हें सीएसई से छूट देने का कोई कारण नहीं है।

परिणाम वास्तव में हो सकता है कि के int x = ++i + ++i;लिए अनुकूलित है int __cse = i++; int x = __cse << 1। (सीएसई, इसके बाद दोहराया ताकत में कमी)


ऑब्जेक्ट कोड के बारे में मानक के पास कहने के लिए कुछ नहीं है। यह भाषा की परिभाषा से या उससे संबंधित नहीं है।
दार्शनिक

1
@philipxy: किसी भी प्रकार के अपरिभाषित व्यवहार के बारे में मानक के पास कहने के लिए कुछ नहीं है। यही प्रश्न का आधार है।
MSalters

7

व्यवहार में, आप अपरिभाषित व्यवहार का आह्वान कर रहे हैं। कुछ भी हो सकता, न सिर्फ चीजें हैं जो आप समझते हैं "उचित", और अक्सर बातें करते हो कि आप उचित नहीं मानते हैं। सब कुछ परिभाषा "उचित" से है।

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

Downvoter: GCC आपसे बहुत असहमत है।


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

6

कोई उचित बात नहीं है कि कोई कंपाइलर 6 का परिणाम पाने के लिए क्या कर सकता है, लेकिन यह संभव और वैध है। 4 का परिणाम पूरी तरह से उचित है, और मैं 5 बॉर्डरलाइन के परिणाम को उचित मानूंगा। वे सभी पूरी तरह से कानूनी हैं।

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

मेमोरी रजिस्टर को दो रजिस्टरों में पढ़ना (या दोनों को एक ही शाब्दिक से शुरू करना, मेमोरी के लिए राउंड ट्रिप को ऑप्टिमाइज़ करना) कंपाइलर के लिए बहुत ही उचित बात है। यह प्रभावी रूप से दो अलग-अलग चर होने का प्रभाव होगा , प्रत्येक 2 के मूल्य के साथ, जो अंत में 4 के परिणाम में जोड़ा जाएगा। यह "उचित" है क्योंकि यह तेज और कुशल है, और यह दोनों के अनुसार है मानक और कोड के साथ।

इसी तरह, मेमोरी लोकेशन को एक बार पढ़ा जा सकता है (या शाब्दिक से वैरिएबल इनिशियलाइज़ किया गया है) और एक बार इंक्रीमेंट किया गया है, और दूसरे रजिस्टर में एक शैडो कॉपी उसके बाद बढ़ाई जा सकती है, जिसके परिणामस्वरूप 2 और 3 को एक साथ जोड़ा जाएगा। यह है, मैं कहूंगा, सीमावर्ती उचित, हालांकि पूरी तरह से कानूनी। मैं इसे उचित मानता हूं क्योंकि यह एक या दूसरे का नहीं है। यह न तो "उचित" अनुकूलित तरीका है, और न ही यह "उचित" बिल्कुल पांडित्यपूर्ण तरीका है। यह कुछ हद तक बीच में है।

मेमोरी लोकेशन को दो बार बढ़ाना (जिसके परिणामस्वरूप 3 का मान होता है) और फिर 6 के अंतिम परिणाम के लिए खुद को उस मूल्य को जोड़ना वैध है, लेकिन यह बिल्कुल उचित नहीं है क्योंकि मेमोरी राउंड ट्रिप करना ठीक नहीं है। हालांकि अच्छा स्टोर फॉरवर्डिंग वाले प्रोसेसर पर, यह करने के लिए "उचित" हो सकता है, क्योंकि स्टोर ज्यादातर अदृश्य होना चाहिए ...
जैसा कि संकलक "जानता है" कि यह एक ही स्थान है, यह वेतन वृद्धि का चयन कर सकता है। एक रजिस्टर के भीतर दो बार मूल्य, और फिर इसे खुद के लिए भी जोड़ें। या तो दृष्टिकोण आपको 6 का परिणाम देगा।

संकलक मानक के शब्दांकन द्वारा, आपको ऐसा कोई भी परिणाम देने की अनुमति देता है, हालाँकि मैं व्यक्तिगत रूप से 6 बहुत ज्यादा "बकवास" पर विचार करूंगा, जो आपत्तिजनक विभाग से याद करते हैं, क्योंकि यह एक अप्रत्याशित चीज है (कानूनी या नहीं) हमेशा आश्चर्य की कम से कम राशि देने की कोशिश करना एक अच्छी बात है!)। हालांकि, यह देखते हुए कि अपरिभाषित व्यवहार कैसे शामिल है, दुख की बात है कि वास्तव में "अप्रत्याशित", एह के बारे में बहस नहीं की जा सकती है।

तो, वास्तव में, आपके पास जो कोड है, वह कंपाइलर के पास क्या है? आइए क्लैग से पूछें, जो हमें दिखाएगा अगर हम अच्छी तरह से पूछें (साथ में -ast-dump -fsyntax-only):

ast.cpp:4:9: warning: multiple unsequenced modifications to 'i' [-Wunsequenced]
int x = ++i + ++i;
        ^     ~~
(some lines omitted)
`-CompoundStmt 0x2b3e628 <line:2:1, line:5:1>
  |-DeclStmt 0x2b3e4b8 <line:3:1, col:10>
  | `-VarDecl 0x2b3e430 <col:1, col:9> col:5 used i 'int' cinit
  |   `-IntegerLiteral 0x2b3e498 <col:9> 'int' 1
  `-DeclStmt 0x2b3e610 <line:4:1, col:18>
    `-VarDecl 0x2b3e4e8 <col:1, col:17> col:5 x 'int' cinit
      `-BinaryOperator 0x2b3e5f0 <col:9, col:17> 'int' '+'
        |-ImplicitCastExpr 0x2b3e5c0 <col:9, col:11> 'int' <LValueToRValue>
        | `-UnaryOperator 0x2b3e570 <col:9, col:11> 'int' lvalue prefix '++'
        |   `-DeclRefExpr 0x2b3e550 <col:11> 'int' lvalue Var 0x2b3e430 'i' 'int'
        `-ImplicitCastExpr 0x2b3e5d8 <col:15, col:17> 'int' <LValueToRValue>
          `-UnaryOperator 0x2b3e5a8 <col:15, col:17> 'int' lvalue prefix '++'
            `-DeclRefExpr 0x2b3e588 <col:17> 'int' lvalue Var 0x2b3e430 'i' 'int'

जैसा कि आप देख सकते हैं, एक ही lvalue Var 0x2b3e430उपसर्ग ++को दो स्थानों पर लागू किया गया है, और ये दोनों पेड़ में एक ही नोड से नीचे हैं, जो एक बहुत ही गैर-विशेष ऑपरेटर (+) होता है जिसमें अनुक्रमण या ऐसे के बारे में कुछ विशेष नहीं कहा जाता है। यह महत्वपूर्ण क्यों है? खैर, पर पढ़ें।

चेतावनी पर ध्यान दें: "'I' के लिए कई अनपेक्षित संशोधन" ओह, यह अच्छा नहीं लगता। इसका क्या मतलब है? [basic.exec] हमें साइड इफेक्ट्स और सिक्वेंसिंग के बारे में बताता है, और यह हमें (पैराग्राफ 10) बताता है कि डिफ़ॉल्ट रूप से, जब तक कि स्पष्ट रूप से अन्यथा नहीं कहा जाता है, व्यक्तिगत ऑपरेटरों के ऑपरेंड और व्यक्तिगत अभिव्यक्तियों के सबएक्सप्रेस के मूल्यांकन के बिना परिणाम हैं । खैर, रफ़ू, यही बात है operator+- कुछ भी नहीं कहा जा रहा है, इसलिए ...

लेकिन क्या हम अनुक्रम-पहले, अनिश्चितकालीन-अनुक्रमित, या परिणाम-रहित के बारे में परवाह करते हैं? वैसे भी कौन जानना चाहता है?

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


"वाजिब" का उपयोग किसी को यह कहने से रोकने के लिए था कि "कंपाइलर कुछ भी कर सकता है, यहां तक ​​कि एकल निर्देश 'सेट x से 7.' का भी उत्सर्जन करें। शायद मुझे स्पष्ट करना चाहिए था।
दालचीनी

@cinnamon कई साल पहले, जब मैं छोटा था और अनुभवहीन था, सन में कंपाइलर इंजीनियरों ने मुझे बताया कि उनके कंपाइलर ने अपरिभाषित व्यवहार के लिए बिल्कुल उचित उत्पादन कोड का काम किया, जो मुझे उस समय अनुचित लगा। सबक सीखा।
gnasher729

ऑब्जेक्ट कोड के बारे में मानक के पास कहने के लिए कुछ नहीं है। यह खंडित और अस्पष्ट है कि आपके सुझाए गए कार्यान्वयन किस तरह से या भाषा की परिभाषा से संबंधित हैं।
फिलीपिक्सी

@philipxy: मानक परिभाषित करता है कि अच्छी तरह से गठित और अच्छी तरह से परिभाषित क्या है और क्या नहीं है। इस क्यू के मामले में, यह अपरिभाषित के रूप में व्यवहार को परिभाषित करता है। कानूनी होने के अलावा, कुशल कोड बनाने वाले संकलक की उचित धारणा भी है। हां, आप सही हैं, मानक को ऐसा करने की आवश्यकता नहीं है। यह एक उचित धारणा है।
डेमन

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

1

एक नियम है :

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

इस प्रकार भी x = 100 एक संभावित वैध परिणाम है।

मेरे लिए उदाहरण में सबसे तार्किक परिणाम 6 है, क्योंकि हम दो बार i के मूल्य में वृद्धि कर रहे हैं और वे इसे खुद से जोड़ते हैं। "+" के दोनों किनारों से गणना मूल्यों से पहले इसके अलावा करना मुश्किल है।

लेकिन कंपाइलर डेवलपर्स किसी अन्य तर्क को लागू कर सकते हैं।


0

ऐसा लगता है कि ++ मैं एक प्रतिफल देता है लेकिन i ++ एक प्रतिफल देता है।
तो यह कोड ठीक है:

int i = 1;
++i = 10;
cout << i << endl;

यह एक नहीं है:

int i = 1;
i++ = 10;
cout << i << endl;

उपरोक्त दोनों कथन VisualC ++, GCC7.1.1, CLang और Embarcadero के अनुरूप हैं।
यही कारण है कि VisualC ++ और GCC7.1.1 में आपका कोड निम्नलिखित के समान है

int i = 1;
... do something there for instance: ++i; ++i; ...
int x = i + i;

डिसएफ़ॉर्मेशन को देखते समय, यह पहले i को बढ़ाता है, फिर से लिखता है। जब इसे जोड़ने की कोशिश की जाती है तो वही काम करता है, जो मैं बढ़ाता हूं और इसे फिर से लिखता हूं। फिर मुझे i से जोड़ता है। मैंने देखा है कि क्लैंग और एम्बरकैरो अलग तरह से काम करते हैं। तो यह पहले बयान के अनुरूप नहीं है, पहले ++ के बाद मैं परिणाम को एक प्रतिद्वंद्विता में संग्रहीत करता है और फिर इसे दूसरे i ++ में जोड़ता है।
यहाँ छवि विवरण दर्ज करें


"लुक लाइन ए लवल्यू" के साथ समस्या यह है कि आप सी ++ मानक के परिप्रेक्ष्य से बात कर रहे हैं, न कि संकलक।
एमएसलटर्स

@MSalters स्टेटमेंट VisualStudio 2019, GCC7.1.1, क्लैंग और एम्बरकैरो के साथ और कोड के पहले टुकड़े के अनुरूप है। इसलिए विनिर्देशन सुसंगत है। लेकिन यह कोड के दूसरे टुकड़े के लिए अलग तरह से काम करता है। कोड का दूसरा टुकड़ा VisualStudio 2019 और GCC7.1.1 के साथ संगत है, लेकिन क्लैंग और एम्बरकैडरो के अनुरूप नहीं है।
आर्मगेडेस्क्यू

3
ठीक है, आपके उत्तर में कोड का पहला टुकड़ा कानूनी सी ++ है, इसलिए स्पष्ट रूप से कार्यान्वयन विनिर्देश के अनुरूप हैं। प्रश्न के अनुसार, आपका "कुछ करें" अर्धविराम में समाप्त होता है, जिससे यह पूर्ण विवरण बन जाता है। यह एक अनुक्रमण बनाता है जो C ++ मानक द्वारा आवश्यक है, लेकिन प्रश्न में मौजूद नहीं है।
एमएसएलटर्स

@ मैं इसे एक समान छद्म कोड के रूप में करना चाहता था। फिर भी मुझे यकीन नहीं है कि इसे कैसे
सुधारना है

0

मैं व्यक्तिगत रूप से आपके उदाहरण में 6 के संकलक की उम्मीद नहीं करूंगा। आपके प्रश्न के अच्छे और विस्तृत उत्तर पहले से ही हैं। मैं एक छोटे संस्करण की कोशिश करूंगा।

मूल रूप से, ++iइस संदर्भ में 2-चरणीय प्रक्रिया है:

  1. के मूल्य में वृद्धि i
  2. का मूल्य पढ़ें i

++i + ++iमानक के अनुसार किसी भी क्रम में जोड़ के दो पक्षों के संदर्भ में मूल्यांकन किया जा सकता है। इसका मतलब है कि दो वेतन वृद्धि स्वतंत्र मानी जाती है। साथ ही, दोनों शर्तों के बीच कोई निर्भरता नहीं है। iइसलिए वेतन वृद्धि और पढ़ा जा सकता है। यह संभावित आदेश देता है:

  1. iबाएं ऑपरेंड के लिए वृद्धि
  2. iसही ऑपरेंड के लिए वृद्धि
  3. iबाएं ऑपरेंड के लिए वापस पढ़ें
  4. iसही ऑपरेंड के लिए वापस पढ़ें
  5. दोनों को जोड़ो: 6 पैदावार

अब, मैं इस बारे में सोचता हूं, 6 मानक के अनुसार सबसे अधिक समझ में आता है। 4 के परिणाम के लिए हमें एक सीपीयू की आवश्यकता होती है जो पहले iस्वतंत्र रूप से पढ़ता है , फिर वृद्धि करता है और उसी स्थान पर वापस मान लिखता है; मूल रूप से एक दौड़ की स्थिति। 5 के मूल्य के लिए हमें एक संकलक की आवश्यकता होती है जो अस्थायी लोगों का परिचय देता है।

लेकिन, मानक कहता है कि ++iचर को वापस करने से पहले बढ़ाता है, अर्थात वर्तमान कोड लाइन को निष्पादित करने से पहले। वेतन वृद्धि को लागू करने के बाद योग ऑपरेटर की +आवश्यकता i + iहोती है। मैं कहूंगा कि C ++ को चर पर काम करने की जरूरत है न कि किसी मूल्य शब्दार्थ पर। इसलिए, मेरे लिए 6 अब सबसे अधिक समझ में आता है क्योंकि यह भाषा के शब्दार्थों पर निर्भर करता है न कि सीपीयू के निष्पादन मॉडल पर।


0
#include <stdio.h>


void a1(void)
{
    int i = 1;
    int x = ++i;
    printf("i=%d\n",i);
    printf("x=%d\n",x);
    x = x + ++i;    // Here
    printf("i=%d\n",i);
    printf("x=%d\n",x);
}


void b2(void)
{
    int i = 1;
    int x = ++i;
    printf("i=%d\n",i);
    printf("x=%d\n",x);
    x = i + ++i;    // Here
    printf("i=%d\n",i);
    printf("x=%d\n",x);
}


void main(void)
{
    a1();
    // b2();
}

Stackoverflow पर आपका स्वागत है! क्या आप अपने उत्तर में कोई सीमाएँ, मान्यताएँ या सरलीकृतियाँ प्रदान कर सकते हैं। इस लिंक पर जवाब देने के तरीके के बारे में अधिक जानकारी देखें: stackoverflow.com/help/how-to-answer
Usama Abdulrehman

0

अच्छी तरह से यह कंपाइलर के डिज़ाइन पर निर्भर करता है। इसके अलावा उत्तर कंपाइलर के डिकोड करने के तरीके पर निर्भर करेगा। तर्क बनाने के लिए दो अलग-अलग वेरिएबल्स ++ x और ++ y का उपयोग करना बेहतर विकल्प होगा। नोट: ouput एमएस विज़ुअल स्टूडियो में भाषा के नवीनतम संस्करण के संस्करण पर निर्भर करता है यदि इसका अद्यतन किया जाता है। यदि नियम बदले गए हैं तो क्या आउटपुट होगा


0

इसे इस्तेमाल करे

int i = 1;
int i1 = i, i2 = i;   // i1 = i2 = 1
++i1;                 // i1 = 2
++i2;                 // i2 = 2
int x = i1 + i2;      // x = 4

0

मूल्यांकन के इस लिंक क्रम से :

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

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

लेकिन, यदि सबएक्सप्रेस एक्सपे 1 और एक्सप 2 के बीच एक अनुक्रम बिंदु मौजूद है, तो एक्सपी 1 के मूल्य गणना और साइड इफेक्ट्स दोनों एक्सपैक्ट 2 के मूल्य मान और साइड इफेक्ट से पहले अनुक्रमित होते हैं।


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

आपकी टिप्पणी मेरे किसी भी मुद्दे को संबोधित नहीं करती है। जिसमें कोड अपरिभाषित नहीं है और अनिर्दिष्ट नहीं है।
दीक्षा छंद

उद्धरण अपरिभाषित का उल्लेख नहीं करते हैं, वे अनिर्दिष्ट उल्लेख करते हैं। मेरा हो गया।
फिलीपिक्‍स

हां, यह अनिर्दिष्ट है, इसीलिए अलग-अलग संकलक के मूल्यांकन के विभिन्न आदेश निहित हैं। इसलिए आपको अलग-अलग कंपाइलरों के लिए अलग-अलग आउटपुट मिलेगा।
कृष्ण कंठ येनुमुला


-4

व्यवहार में, आप अपरिभाषित व्यवहार का आह्वान कर रहे हैं। कुछ भी हो सकता, न सिर्फ चीजें हैं जो आप समझते हैं "उचित", और अक्सर बातें करते हो कि आप उचित नहीं मानते हैं। सब कुछ परिभाषा "उचित" से है।

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


1
मेरा मानना ​​है कि आपने प्रश्न को गलत समझा है। प्रश्न सामान्य या विशिष्ट व्यवहार के बारे में है जो विशिष्ट परिणामों (x = 4, 5 या 6 के परिणाम) को जन्म दे सकता है। यदि आपको "वाजिब" शब्द का मेरा उपयोग पसंद नहीं है, तो मैं आपको अपनी टिप्पणी के लिए ऊपर निर्देशित करता हूं, जिसका आपने उत्तर दिया है: "'वाजिब' का उपयोग किसी को भी यह कहने से रोकना था कि 'कंपाइलर कुछ भी कर सकता है, जैसे" यहां तक ​​कि सिंगल इंस्ट्रक्शन '' सेट x से 7. तक '' का उत्सर्जन करें यदि आपके पास सामान्य विचार को बनाए रखने वाले प्रश्न के लिए बेहतर शब्दांकन है, तो मैं इसके लिए खुला हूं। इसके अलावा, ऐसा प्रतीत होता है कि आपने अपना उत्तर पुनः पोस्ट कर दिया है।
दालचीनी

2
अपने दो उत्तरों में से एक को हटाने का सुझाव दें क्योंकि वे दोनों बहुत समान हैं
MM
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.