C और C ++ में + का क्या परिणाम है?


93

मुझे निम्नलिखित कोड मिला है:

#include <stdio.h>
int main(int argc, char **argv) {
    int i = 0;
    (i+=10)+=10;
    printf("i = %d\n", i);
    return 0;
}

अगर मैं इसे एक सी स्रोत के रूप में संकलित करने का प्रयास करता हूं, तो मुझे एक त्रुटि मिलती है:

error: lvalue required as left operand of assignment

लेकिन अगर मैं इसे G ++ का उपयोग करके C ++ स्रोत के रूप में संकलित करता हूं तो मुझे कोई त्रुटि नहीं मिलती है और जब मैं निष्पादन योग्य चलता हूं:

i = 20

अलग व्यवहार क्यों?


85
अलग भाषा, अलग वाक्यविन्यास नियम ?. व्यक्तिगत रूप से, मैं कोड-समीक्षा में उस कोड को अस्वीकार कर दूंगा।
अधिकतम

7
इस imo जैसे कोड से बचें ... सभी के लिए अस्पष्ट।
अलायर्स

1
निस्संदेह, कोड साफ नहीं है और इसे "वास्तविक" विकास से बचना चाहिए। लेकिन फिर भी, मैं एक ही व्यवहार का पालन करता हूं और इसके कारणों को जानना चाहूंगा।
ulidtko

9
यह सॉफ्टवेयर के वास्तविक टुकड़े से एक अंश नहीं है। यह सिर्फ एक किंक है जो मैंने गलती से ठोकर खाई है।
स्वेतलिन म्लादेनोव

3
@ जॉनडब्लिंग मुझे लगता है कि अपवोट विशेष रूप से (i + = 10) + = 10 है, मुझे नहीं पता कि कौन सी भाषा है जो कि वैध कोड है और इस तथ्य के बारे में कि वह कहती है कि सी ++ वास्तव में इसे मेरे बारे में बताती है।
टोनी ३१18

जवाबों:


133

यौगिक असाइनमेंट ऑपरेटरों के शब्दार्थ C और C ++ में भिन्न हैं:

C99 मानक, 6.5.16, भाग 3:

एक असाइनमेंट ऑपरेटर बाएं ऑपरेंड द्वारा निर्दिष्ट ऑब्जेक्ट में एक मान संग्रहीत करता है। एक असाइनमेंट एक्सप्रेशन में असाइनमेंट के बाद लेफ्ट ऑपरेंड का मूल्य होता है, लेकिन यह एक अंतराल नहीं है।

C ++ में 5.17.1:

असाइनमेंट ऑपरेटर (=) और कंपाउंड असाइनमेंट ऑपरेटर सभी ग्रुप को राइट-टू-लेफ्ट करते हैं। सभी को अपने बाएं ऑपरेंड के रूप में एक मोडी लेवल्यू की आवश्यकता होती है और असाइनमेंट होने के बाद लेफ्ट ऑपरेंड के प्रकार और मान के साथ एक लैवल्यू लौटाते हैं।

EDIT:(i+=10)+=10 C ++ का व्यवहार C ++ 98 में अपरिभाषित है, लेकिन C ++ 11 में अच्छी तरह से परिभाषित है। मानकों के प्रासंगिक भागों के लिए NPE द्वारा प्रश्न का यह उत्तर देखें ।


सही बात। एक परिणाम मान लौटाता है, और एक चर (पता)
टेक्ससब्रूस

7
महत्वपूर्ण : ध्यान दें कि (i+=10)+=10C ++ में अपरिभाषित व्यवहार है, @aix उत्तर देखें।
डेविड रॉड्रिग्ज -

@ DavidRodríguez-dribeas आपका मतलब अनिर्दिष्ट था , अपरिभाषित नहीं , सही?
dasblinkenlight

4
@dasblinkenlight: नहीं, उनका मतलब अपरिभाषित था । C ++ 03 और पूर्व में, एक अभिव्यक्ति के अंतराल परिणाम को संशोधित करते हुए हस्तक्षेप करने वाले अनुक्रम बिंदु की कमी के कारण सभी संकलक में अप्रत्याशित रूप से व्यवहार किया जाता है। यदि यह अनिर्दिष्ट था , तो यह अनुमानित रूप से अलग-अलग लेकिन अलग-अलग संकलक पर व्यवहार करेगा ।
जस्टिन ᚅᚔᚈᚄᚒᚔ

2
यह एक सेटिंग में उपयोगी होता है जैसे int f(int &y); f(x += 10);- किसी फ़ंक्शन में संशोधित चर के संदर्भ को पास करना।
फिल मिलर

51

सी कोड अमान्य होने के अलावा, लाइन

(i+=10)+=10;

यह C और C ++ 03 दोनों में अपरिभाषित व्यवहार का परिणाम होगा क्योंकि यह iअनुक्रम बिंदुओं के बीच दो बार संशोधित होगा ।

जैसे कि इसे C ++ में संकलित करने की अनुमति क्यों है:

[C ++ N3242 5.17.1] असाइनमेंट ऑपरेटर (=) और कंपाउंड असाइनमेंट ऑपरेटर सभी ग्रुप को राइट-टू-लेफ्ट करते हैं। सभी को अपने बाएं ऑपरेंड के रूप में एक परिवर्तनीय अंतराल की आवश्यकता होती है और बाएं ऑपरेंड का जिक्र करते हुए एक अंतराल वापस करता है।

यही पैराग्राफ आगे कहते हैं कि

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

यह बताता है कि C ++ 11 में, अभिव्यक्ति का अब अपरिभाषित व्यवहार नहीं है।


3
ठीक है, यह निश्चित रूप से अनुक्रम बिंदुओं के कारण यूबी है। यह C (लेकिन C ++ नहीं) में भी अमान्य कोड है , लेकिन यह अनुक्रम बिंदुओं से असंबंधित है, और संकलक द्वारा पकड़ा जाना चाहिए।
कोनराड रुडोल्फ

2
@KonradRudolph: नहीं, कंपाइलर अपरिभाषित व्यवहार को पकड़ने के लिए बाध्य नहीं है, जैसा कि बीमार-निर्मित कोड के विपरीत है। "संकलक द्वारा पकड़ा जाना चाहिए" भाग वह है जहां हम असहमत हैं।

2
सी ++ 11 में अनुक्रम बिंदु मौजूद नहीं हैं, इसलिए यूबी के लिए वास्तविक कारण यह है कि इसके लिए दो संशोधन iहैं।
मकारसे

4
यह गलत है कि यह अपरिभाषित व्यवहार है। यदि असाइनमेंट को असाइनमेंट एक्सप्रेशन की वैल्यू कम्प्यूटेशन से पहले अनुक्रम नहीं किया गया था तो i = j+=1एक अनिश्चित मूल्य होगा। उसी पैराग्राफ से आप उद्धृत करते हैं "सभी मामलों में, असाइनमेंट को दाएं और बाएं ऑपरेंड्स के मूल्य गणना के बाद, और असाइनमेंट एक्सप्रेशन के मूल्य गणना से पहले अनुक्रमित किया जाता है।" इसलिए करने के (i+=10)+=10लिए अच्छी तरह से परिभाषित किया गया है i += 10; i += 10;। दूसरी तरफ (i+=10)+=(i+=10)यूबी है।
bames53

2
चूंकि मैंने देखा कि टिप्पणीकारों के बीच इस पर कुछ मतभेद था, इसलिए मैंने इसे एक अलग प्रश्न के रूप में पोस्ट किया है: stackoverflow.com/questions/10655290/…
NPE
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.