+ (+ k--) C में अभिव्यक्ति


9

मैंने इस प्रश्न को एक परीक्षण में देखा जिसमें हमें निम्नलिखित कोड का आउटपुट बताना है।

#include<stdio.h>

int main(){
    int k = 0;
    while(+(+k--)!=0)
    k=k++;
    printf("%d\n", k);  
    return 0;
}

आउटपुट है -1। मैं अनिश्चित हूं कि यह उत्तर क्यों है, हालांकि।

+(+k--)C में अभिव्यक्ति का क्या अर्थ है?


4
क्या इसे इस तरह से स्वरूपित किया गया था? इसका मतलब ;-)
पीटर -

3
संकेत: वास्तविक जीवन में कभी भी बीएस कोड इस तरह न लिखें।
Jabberwocky

5
यह यूबी नहीं है । मेरा जवाब देखिए।
dbush

@ पीटर-रेनटामेटोनिका हाँ, इसे इस तरह स्वरूपित किया गया था।
अंकुर गौतम

2
क्योंकि इसके आकस्मिक प्रकृति और विचित्र मोड़ के कारण - k=k++अपरिभाषित है, लेकिन यह अपरिभाषित नहीं है, क्योंकि यह कभी भी एक अव्यवस्थित स्थिति के कारण निष्पादित नहीं किया जाता है - मैं इस प्रश्न के डुप्लिकेट के रूप में बंद करने के लिए मतदान कर रहा हूं ।
स्टीव समिट

जवाबों:


10

[रिकॉर्ड के लिए, मैंने इस उत्तर को काफी महत्वपूर्ण रूप से संपादित किया है क्योंकि इसे स्वीकार किया गया था और इस पर मतदान किया गया था। यह अभी भी मूल रूप से वही बातें कहता है, हालांकि।]

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

कोड के दो भ्रामक पहलू हैं, अजीब स्थिति:

while(+(+k--)!=0)

और यह नियंत्रित नियंत्रण कथन:

k=k++;

मैं पहले भाग को कवर करने जा रहा हूं।

यदि आपके पास एक चर है जैसे kआप 1 से बढ़ाना चाहते हैं, तो सी आपको एक नहीं, दो नहीं, तीन नहीं, बल्कि इसे करने के चार अलग-अलग तरीके देता है:

  1. k = k + 1
  2. k += 1
  3. ++k
  4. k++

इस इनाम के बावजूद (या शायद इसकी वजह से), कुछ प्रोग्रामर भ्रमित हो जाते हैं और गर्भनिरोध जैसे खांसी करते हैं

k = k++;

यदि आप यह पता नहीं लगा सकते हैं कि यह क्या करना है, तो चिंता न करें: कोई भी नहीं कर सकता है। इस अभिव्यक्ति में k's मान ( k =भाग, और k++भाग) को बदलने के दो अलग-अलग प्रयास शामिल हैं , और क्योंकि C में कोई नियम नहीं है जो यह कहता है कि कौन से प्रयास "जीत" हुए हैं, इस तरह का एक अभिव्यक्ति औपचारिक रूप से अपरिभाषित है , जिसका अर्थ केवल इतना ही नहीं है इसका कोई अर्थ नहीं है, लेकिन इसका पूरा कार्यक्रम संदिग्ध है।

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

इस तरह के अपरिभाषित व्यवहार के विषय में सभी प्रश्नों के उत्तर भी देखें ।

लेकिन आपने k=k++भाग के बारे में नहीं पूछा । आपने पहले भ्रमित करने वाले भाग, +(+k--)!=0स्थिति के बारे में पूछा । यह अजीब लग रहा है, क्योंकि यह है अजीब। कोई भी कभी भी, वास्तविक कार्यक्रम में ऐसा कोड नहीं लिखेगा। इसलिए इसे समझने का कोई कारण नहीं है। (हां, इसकी सही, एक प्रणाली की सीमाओं की खोज आपको इसके ठीक बिंदुओं के बारे में जानने में मदद कर सकती है, लेकिन मेरी किताब में कल्पनाशील, विचार-विहीन अन्वेषण बनाम गंदे, अपमानजनक अन्वेषणों के बीच एक स्पष्ट रेखा है, और यह अभिव्यक्ति बहुत स्पष्ट रूप से है उस लाइन का गलत पक्ष।)

वैसे भी, चलो जांच करते हैं +(+k--)!=0। (और ऐसा करने के बाद, चलो इसके बारे में सब भूल जाते हैं।) इस तरह की किसी भी अभिव्यक्ति को अंदर से बाहर समझना होगा। मुझे लगता है आप जानते हैं कि क्या

k--

कर देता है। यह kवर्तमान मूल्य लेता है और इसे बाकी की अभिव्यक्ति में "वापस" करता है, और यह कम या ज्यादा एक साथ घटता है k, यानी यह मात्रा को k-1वापस स्टोर करता है k

लेकिन फिर क्या करता +है? यह एकात्मक प्लस है, न कि बाइनरी प्लस। यह सिर्फ एक शून्य के समान है। आप जानते हैं कि बाइनरी माइनस घटाव: अभिव्यक्ति है

a - b

एक से घटाव b। और आप जानते हैं कि एकात्मक ऋण चीजों को नकारता है: अभिव्यक्ति

-a

आपको एक का नकारात्मक देता है। क्या एकता +है ... मूल रूप से कुछ भी नहीं है। सकारात्मक मूल्यों को सकारात्मक और नकारात्मक मूल्यों को नकारात्मक में बदलने के बाद +aआपको aमूल्य देता है । तो अभिव्यक्ति

+k--

आपको जो कुछ भी k--दिया है, वह आपको देता है , जो कि kपुराना है।

लेकिन हम नहीं कर रहे हैं, क्योंकि हमारे पास है

+(+k--)

यह बस +k--आपको जो कुछ भी दिया गया है, उसे लेता है और +फिर से इस पर लागू होता है । तो यह आपको वह देता है जो आपने +k--दिया था, जो कुछ भी k--आपको दिया था, जो kपुराना था ।

तो अंत में, हालत

while(+(+k--)!=0)

बिल्कुल वैसा ही काम करता है जैसा कि बहुत अधिक सामान्य स्थिति में होता है

while(k-- != 0)

किया होता। (यह वही काम भी करता है जो और भी जटिल-सी दिखने वाली स्थिति while(+(+(+(+k--)))!=0)ने किया होगा। और वे कोष्ठक वास्तव में आवश्यक नहीं हैं; यह भी वही काम करता है while(+ + + +k--!=0)जो उसने किया होगा।)

यहां तक ​​कि यह पता लगाना कि "सामान्य" स्थिति क्या है

while(k-- != 0)

है एक तरह से मुश्किल। इस लूप में दो चीजें चल रही हैं: जैसा कि लूप संभावित रूप से कई बार चलता है, हम इस पर जा रहे हैं:

  1. छोटे और छोटे k--बनाने के लिए k, लेकिन यह भी करते रहें
  2. जो भी करता है, पाश के शरीर को करते रहो।

लेकिन हम इस k--भाग को तुरंत (पहले की प्रक्रिया में) तय करते हैं कि लूप के माध्यम से दूसरी यात्रा करना है या नहीं। और याद रखें कि k--"रिटर्न" पुराने मूल्य का k, इसे घटाने से पहले। इस कार्यक्रम में, का प्रारंभिक मान k0. है। इसलिए k--पुराने मान 0 को "वापस" करने जा रहा है, फिर k-1 पर अपडेट करें। लेकिन फिर बाकी हालत यह है != 0- लेकिन जैसा कि हमने अभी देखा, पहली बार जब हमने स्थिति का परीक्षण किया, तो हमें एक 0. मिला। इसलिए हम लूप के माध्यम से कोई यात्रा नहीं करेंगे, इसलिए हम इसे निष्पादित करने का प्रयास नहीं करेंगे समस्यात्मक बयान k=k++

दूसरे शब्दों में, इस विशेष लूप में, हालांकि मैंने कहा कि "दो तरह की चीजें चल रही हैं", यह पता चला है कि 1 चीज एक बार होती है, लेकिन 2 चीज शून्य बार होती है।

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


1
किसी भी संस्थापक वर्ग में योगदान वाले उदाहरण विशिष्ट हैं। किसी अन्य व्यक्ति ने किसी परीक्षा पर ऑपरेटर की पूर्ववर्ती स्थिति पर एक संक्षिप्त प्रश्न कैसे लिखा होगा ? मैं गणित पढ़ाता हूं, और अगर मेरे पास हर बार एक छात्र के लिए एक निकल था "जब मैं वास्तविक जीवन में ऐसा करने जा रहा हूं ?"
स्कॉट

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

1
"मैं अपनी राय से खड़ा हूं" यह उचित है, लेकिन यहां कीवर्ड "राय" है। एक StackOverflow उत्तर शायद किसी की राय व्यक्त करने के लिए इष्टतम जगह नहीं है। :)
स्कॉट

1
रिकॉर्ड के लिए, मैंने इस उत्तर को काफी हद तक संपादित किया है क्योंकि इसे स्वीकार किया गया था और इस पर मतदान किया गया था। यह अभी भी मूल रूप से एक ही बातें कहता है, यद्यपि।
स्टीव समिट

11

पहली नज़र में ऐसा लग रहा है कि यह कोड अपरिभाषित व्यवहार को आमंत्रित करता है लेकिन ऐसा नहीं है।

पहले कोड को सही ढंग से प्रारूपित करें:

#include<stdio.h>

int main(){
    int k = 0;
    while(+(+k--)!=0)
        k=k++;
    printf("%d\n", k);  
    return 0;
}

तो अब हम देख सकते हैं कि स्टेटमेंट k=k++;लूप के अंदर है।

अब आइए कार्यक्रम को ट्रेस करें:

जब लूप स्थिति का पहले मूल्यांकन किया जाता है, kतो मान 0 होता है। अभिव्यक्ति k--का वर्तमान मान होता है k, जो 0 है, और kएक साइड इफेक्ट के रूप में घटाया जाता है। तो इस कथन के बाद का मान k-1 है।

+इस अभिव्यक्ति पर अग्रणी का मूल्य पर कोई प्रभाव नहीं होता है, इसलिए +k--0 का मूल्यांकन किया जाता है और इसी तरह 0 का +(+k--)मूल्यांकन किया जाता है।

फिर !=ऑपरेटर का मूल्यांकन किया जाता है। चूंकि 0!=0झूठ है, लूप के शरीर में प्रवेश नहीं किया जाता है । यदि शरीर में प्रवेश किया गया था, तो आप अपरिभाषित व्यवहार का आह्वान करेंगे क्योंकि k=k++दोनों kअनुक्रम बिंदु के बिना पढ़ते और लिखते हैं । लेकिन लूप दर्ज नहीं किया गया है, इसलिए कोई यूबी नहीं।

अंत में मूल्य का kप्रिंट होता है जो -1 है।


1
यह एक खुला, अस्तित्ववादी, दार्शनिक, अभेद्य प्रश्न है कि क्या अपरिभाषित व्यवहार जिसे निष्पादित नहीं किया गया है, अपरिभाषित नहीं है। क्या यह अपरिभाषित नहीं है? मुझे ऐसा नहीं लगता।
स्टीव समिट

2
@SteveSummit इसके बारे में बिल्कुल मौजूद, दार्शनिक, असंभव कुछ भी नहीं है। if (x != NULL) *x = 42;क्या यह अपरिभाषित है x == NULL? बिलकूल नही। अपरिभाषित व्यवहार कोड के उन हिस्सों में नहीं होता है जो निष्पादित नहीं होते हैं। शब्द व्यवहार एक संकेत है। जिस कोड को निष्पादित नहीं किया गया है उसका कोई व्यवहार नहीं है, अपरिभाषित या अन्यथा।
एन। 'सर्वनाम' मी।

1
@SteveSummit यदि अपरिभाषित व्यवहार जिसे निष्पादित नहीं किया गया है तो पूरे कार्यक्रम को अमान्य कर दिया जाएगा, किसी भी C प्रोग्राम ने व्यवहार को परिभाषित नहीं किया होगा। क्योंकि C प्रोग्राम हमेशा सिर्फ एक लूप होते हैं / यदि हालत UB निष्पादित करने से दूर हो। उदाहरण के लिए एक साधारण सरणी पुनरावृत्ति लें: यह तब तक पुनरावृत्त होता है जब तक कि बाउंड चेक विफल न हो जाए। अगले लूप पुनरावृत्ति को निष्पादित करना अपरिभाषित व्यवहार होगा, लेकिन क्योंकि यह कभी निष्पादित नहीं होता है, सब कुछ ठीक है।
विस्फ़ोटक -

3
मैं इसके बारे में बहस नहीं करने जा रहा, क्योंकि मैं भाषा वकील नहीं करता। लेकिन मैंने शर्त लगाई कि अगर आपने यह सवाल पूछा और इसे भाषा-वकील को टैग किया, तो आप एक उत्साही बहस कर सकते हैं। ध्यान दें कि k=k++गुणात्मक रूप से भिन्न है *x=42। उत्तरार्द्ध अच्छी तरह से परिभाषित है अगर xएक वैध सूचक है, लेकिन पूर्व अपरिभाषित है कोई फर्क नहीं पड़ता कि क्या। (मैं मानता हूं कि आप सही हो सकते हैं, लेकिन फिर से, मैं इस पर बहस नहीं करने जा रहा हूं, और मैं तेजी से चिंतित हूं कि हमें मास्टर ट्रोल किया गया है।)
स्टीव समिट

1
"बाद में अच्छी तरह से परिभाषित किया जाता है अगर x एक वैध सूचक है, लेकिन पूर्व अपरिभाषित है कोई बात नहीं"। केवल पूरे कार्यक्रमों में अपरिभाषित व्यवहार हो सकता है। यह धारणा अलगाव में लिए गए कोड अंशों पर लागू नहीं है।
एन। 'सर्वनाम' मी।

3

यहां इसका एक संस्करण है जो ऑपरेटर की पूर्वता दिखाता है:

+(+(k--))

दो यूनीरी +ऑपरेटर कुछ भी नहीं करते हैं, इसलिए यह अभिव्यक्ति बिल्कुल बराबर है k--। जिस व्यक्ति ने यह लिखा है, वह आपके दिमाग में गड़बड़ करने की कोशिश कर रहा है।

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