2010-07-24 15 views
9

मैं निम्नलिखित कोडअभिव्यक्ति का व्यवहार: परिभाषित या अनिर्धारित?

int m[4]={1,2,3,4}, *y; 
y=m; 
*y = f(y++); // Expression A 

मेरे दोस्त ने मुझे बताया Expression A एक अच्छी तरह से परिभाषित व्यवहार है, लेकिन मुझे यकीन है कि क्या वह सही है नहीं कर रहा हूँ कि है।

उनके अनुसार कार्य f() के बीच sequence point प्रस्तुत करता है और इसलिए व्यवहार अच्छी तरह से परिभाषित किया गया है।

कोई कृपया स्पष्ट करें।

पीएस: मुझे पता है कि हमें व्यावहारिक उद्देश्य के लिए ऐसा कोड नहीं लिखना चाहिए। यह सिर्फ सीखने के उद्देश्य के लिए है। :)

+3

मैं नहीं कहता हूं। उस पर 'जीसीसी' मुझे बताता है। – kennytm

उत्तर

15

सबसे अच्छा, प्रश्न में कोड को अनिर्दिष्ट व्यवहार है। असाइनमेंट ऑपरेटरों के लिए, "ऑपरेटरों के मूल्यांकन का आदेश अनिश्चित है" (सी 99 §6.5.16/4)।

यदि बाएं ऑपरेंड का मूल्यांकन पहले किया जाता है, तो f(y++) का परिणाम m[0] में संग्रहीत किया जाएगा। यदि सही ऑपरेंड का मूल्यांकन पहले किया जाता है, तो परिणाम m[1] में संग्रहीत किया जाएगा।

कि क्या व्यवहार अपरिभाषित है का सवाल है, प्रासंगिक पैराग्राफ है:

पिछले और अगले अनुक्रम बिंदु एक वस्तु एक अभिव्यक्ति के मूल्यांकन से अधिकतम एक बार अपने संग्रहीत मूल्य मोदी फाई एड होगा बीच

। इसके अलावा, पूर्व मान केवल संग्रहीत करने के मान को निर्धारित करने के लिए पढ़ा जाएगा (सी 99 §6.5/2)।

बाईं ओर पहला मूल्यांकन किया जाता है, तो हम दूसरे वाक्य के afoul चलाने क्योंकि आदेश है:

  1. y का मूल्य यह भिन्नता
  2. के बाईं ओर पढ़ा जाता है y का मूल्य
  3. फ़ंक्शन के तर्कों के मूल्यांकन के बाद एक अनुक्रम बिंदु है (इसलिए, y++ का साइड इफेक्ट पूरा हो गया है और y को लिखा गया है) 0

चरण 1 में, y का "पूर्व मान" पढ़ा जाता है लेकिन "संग्रहीत करने के लिए मूल्य निर्धारित करने" के अलावा किसी उद्देश्य के लिए। इस प्रकार, व्यवहार वास्तव में अनिर्धारित है क्योंकि एक वैध मूल्यांकन आदेश अपरिभाषित व्यवहार पैदा करता है।

+2

+1। मेरा मानना ​​है कि यह भी अपरिभाषित है, क्योंकि '* y' और' y ++ 'के मूल्यांकन अपूर्ण हैं और बाद वाले' y' पर दुष्प्रभाव उत्पन्न करते हैं। – avakar

+0

धन्यवाद जेम्स, आपका जवाब बिल्कुल ठीक है। एसी :-) –

0

संपादित करें: यह गलत है, हालांकि मैं इसे यहां छोड़ रहा हूं क्योंकि टिप्पणियों में निम्नलिखित चर्चा कुछ हद तक रोशनी है, और मुझे मूल्यवान उम्मीद है।

यह सी (या सी ++) में ऑपरेटरों के मूल्यांकन आदेश के आधार पर अच्छी तरह परिभाषित है।

पहले अभिव्यक्ति के दाईं ओर असाइनमेंट बल मूल्यांकन मूल्यांकन। फंक्शन एप्लिकेशन पहले अपने तर्कों का मूल्यांकन करता है, इसलिए प्रभाव उचित रूप से स्पष्ट लगता है (हालांकि मैंने इसे चलाने की कोशिश नहीं की है, इसलिए मुझे सही करने के लिए स्वतंत्र महसूस करें!)। हम इस अस्थायी वेरिएबल का उपयोग करके फिर से लिखने कर सकते हैं (मैं उन्हें t0 और t1 फोन करता हूँ), और मेरा मानना ​​है कि यह एक छोटे से स्पष्ट हो सकता है:

t0 = y++; 
t1 = f(t0); 
*y = t1; 

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

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

+2

_ अभिव्यक्ति बल दायीं तरफ अभिव्यक्ति के दायीं तरफ मूल्यांकन ._ यह सच नहीं है: मूल्यांकन का आदेश अनिर्दिष्ट है। –

+1

यह कहां कहता है कि किसी असाइनमेंट के दाहिने हाथ का मूल्यांकन पहले किया जाना चाहिए? – jalf

+0

धन्यवाद, मैंने अभी इसके लिए मेरा जवाब संपादित किया है, और मुझे सी के बारे में कुछ नया सिखाने के लिए धन्यवाद :) – Gian

1

अभिव्यक्ति अच्छी तरह से परिभाषित नहीं है:

अभिव्यक्ति का एक मान्य व्याख्या है: अभिव्यक्ति की

(1) int* t0 = y++; 
(2) int t1 = f(t0); 
(3) int& t2 = *y; 
----------------- 
t2 = t1; 

एक समान रूप से मान्य व्याख्या है:

(1) int& t2 = *y; 
(2) int* t0 = y++; 
(3) int t1 = f(t0); 
----------------- 
t2 = t1; 

इन दोनों कर रहे हैं वैदिक और विभिन्न परिणाम उत्पन्न करते हैं। तो अभिव्यक्ति ने परिणाम को अपरिभाषित किया है।

+1

आम तौर पर, तथ्य यह है कि एक अभिव्यक्ति के दो अलग-अलग परिणाम हो सकते हैं इसका मतलब है कि परिणाम * अनिर्दिष्ट * है। हालांकि, इस विशेष मामले में परिणाम वास्तव में अपरिभाषित है क्योंकि 't0' और' t2' की गणना किसी भी क्रम में हो सकती है और 't0' के 'y' पर दुष्प्रभाव होते हैं जबकि' t2' 'y' के मान का उपयोग करता है। – avakar

13

आप अनुक्रम बिंदु को पेश करने वाले फ़ंक्शन कॉल के बारे में बिल्कुल सही हैं। हालांकि, वह अनुक्रम बिंदु आपके मामले में स्थिति को सहेजता नहीं है।

इस सरल पहला उदाहरण

i = some_function(i++); 

यह वैध है पर विचार करें? हाँ यही है। क्यूं कर? यह मान्य है क्योंकि फ़ंक्शन द्वारा प्रस्तुत अनुक्रम बिंदु (जिस पर आप बात कर रहे हैं) एक दूसरे से i के दो संशोधनों को अलग करता है, इस प्रकार कोड को वैध बना देता है। इस अभिव्यक्ति के मूल्यांकन का कोई आदेश नहीं है जिसके परिणामस्वरूप i को अंतःक्रियात्मक अनुक्रम बिंदु के बिना दो बार संशोधित किया जा रहा है।

हालांकि, के इस मामले कि अनुक्रम बिंदु के रूप में अच्छी तरह से मौजूद है में अपने संस्करण

*y = f(y++); 

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

+1

@ बेन वोगेट: मैं '=' ऑपरेटर के संचालन के मूल्यांकन के सापेक्ष आदेश के बारे में बात कर रहा था, यानी एलएचएस या आरएचएस का मूल्यांकन पहले किया गया है या नहीं। – AnT

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