संकलन त्रुटि को c = ++ (a + b) क्यों देता है?


111

शोध करने के बाद, मैंने पढ़ा कि वेतन वृद्धि के लिए ऑपरेटर को एक परिवर्तनीय डेटा ऑब्जेक्ट की आवश्यकता होती है: https://en.wikipedia.org/wiki/Increment_and_decrement_operators

इससे मुझे लगता है कि यह संकलन त्रुटि देता है क्योंकि (a+b)एक अस्थायी पूर्णांक है और इसलिए यह परिवर्तनीय नहीं है।

क्या यह समझ सही है? यह मेरी पहली बार एक समस्या पर शोध करने की कोशिश कर रहा था, इसलिए यदि कोई ऐसी चीज थी जिसे मुझे सलाह के लिए देखना चाहिए था।


35
यह शोध के लिहाज से बुरा नहीं है। आप सही रास्ते पर हैं।
स्टोरीटेलर - Unslander मोनिका

35
आप अभिव्यक्ति की अपेक्षा क्या करते हैं?
qrdl

4
C11 मानक 6.5.3.1 के अनुसार: उपसर्ग वृद्धिशील या
क्रिश्चियन गिब्बल

10
आप कैसे चाहेंगे कि 1 को a और b के बीच वितरित किया जाए? "क्या सरणी सूचकांकों की शुरुआत 0 या 1 से होनी चाहिए? 0.5 का मेरा समझौता बिना खारिज कर दिया गया, मैंने सोचा, उचित विचार।" - स्टेन केली-बूटल
एंड्रयू मोर्टन

5
मुझे लगता है कि सवाल पर एक अनुवर्ती है कि आप ऐसा क्यों करना चाहते हैं जब c = a + b + 1आपका इरादा स्पष्ट हो जाता है और टाइप करने के लिए भी कम है। वेतन वृद्धि / गिरावट ऑपरेटर दो काम करते हैं। वे और उनके तर्क एक अभिव्यक्ति बनाते हैं (जिसका उपयोग किया जा सकता है, उदाहरण के लिए लूप में), 2. वे तर्क को संशोधित करते हैं। आपके उदाहरण में आप संपत्ति 1 का उपयोग कर रहे हैं। लेकिन संपत्ति 2 का नहीं। चूंकि आप संशोधित तर्क को फेंक देते हैं। यदि आपको संपत्ति 2. की आवश्यकता नहीं है और बस अभिव्यक्ति चाहिए, तो आप बस x ++ के बजाय एक अभिव्यक्ति लिख सकते हैं, जैसे x + 1।
ट्रेवर

जवाबों:


117

यह सिर्फ एक नियम है, यह सब है, और संभवतः वहाँ है (1) सी कंपाइलर लिखना आसान है और (2) किसी ने भी सी मानकों समिति को इसे आराम करने के लिए आश्वस्त नहीं किया है।

अनौपचारिक रूप से आप केवल लिख सकते हैं बोल रहा ++fooहै, तो fooजैसे एक काम अभिव्यक्ति की बाएं हाथ की ओर दिखाई दे सकता है foo = bar। चूंकि आप लिख नहीं सकते हैं a + b = bar, आप लिख ++(a + b)भी नहीं सकते ।

इसका कोई वास्तविक कारण a + bनहीं है कि एक अस्थायी उपज क्यों नहीं हो सकती है जिस पर ++काम किया जा सकता है, और उसी का परिणाम अभिव्यक्ति का मूल्य है ++(a + b)


4
मुझे लगता है कि बिंदु (1) सिर पर कील मारता है। सी ++ में अस्थायी भौतिककरण के नियमों को देखने से किसी का पेट पलट सकता है (लेकिन यह शक्तिशाली है, हालांकि, यह कहना होगा)।
स्टोरीटेलर - Unslander मोनिका

4
@StoryTeller: वास्तव में, हमारी प्रिय भाषा C ++ के विपरीत, C अभी भी अपेक्षाकृत तुच्छ रूप से असेंबली में संकलित है।
बाथशीबा

29
यहां एक वास्तविक कारण IMHO है: यह एक भयानक भ्रम होगा यदि ++कभी-कभी कुछ संशोधित करने का एक पक्ष प्रभाव होता है और कभी-कभी बस नहीं होता है।
aschepler

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

6
@ बाथशीबा बताते हैं कि क्यों 5 ++ भी संकलन त्रुटि का कारण बनता है
dng

40

धारा 11.3.3 में C11 मानक बताता है

उपसर्ग वृद्धिशील या वेतन वृद्धि संचालक के पास परमाणु, योग्य, या अयोग्य वास्तविक या सूचक प्रकार होंगे, और एक परिवर्तनीय अंतराल होगा

और "परिवर्तनीय अंतराल" खंड 6.3.2.1 उपधारा 1 में वर्णित है

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

तो (a+b)एक परिवर्तनीय अंतराल नहीं है और इसलिए उपसर्ग वृद्धि वेतन के लिए पात्र नहीं है।


1
इन परिभाषाओं से आपका निष्कर्ष गायब है ... आप यह कहना चाहते हैं कि (a + b) किसी ऑब्जेक्ट को संभावित रूप से नामित नहीं करता है, लेकिन ये पैराग्राफ इसकी अनुमति नहीं देते हैं।
hkBst

21

तुम सही हो। ++मूल चर में नए मान को असाइन करने का प्रयास करता है। तो ++aमान लेगा a, इसमें जोड़ता 1है और फिर इसे वापस असाइन करता है a। चूंकि, जैसा कि आपने कहा, (a + b) एक अस्थायी मान है, और असाइन किए गए मेमोरी पते के साथ एक चर नहीं है जिसे असाइनमेंट नहीं किया जा सकता है।


12

मुझे लगता है कि आपने ज्यादातर अपने सवाल का जवाब दिया। मैं आपके वाक्यांशों में एक छोटा सा परिवर्तन कर सकता हूं और "अस्थायी चर" को "रिबन" से बदल सकता हूं जैसा कि सी। गिबन्स ने उल्लेख किया है।

C के मेमोरी मॉडल के बारे में जानने के दौरान शब्द चर, तर्क, अस्थायी चर और इतने पर और स्पष्ट हो जाएगा (यह एक अच्छा अवलोकन की तरह दिखता है: https://www.geeksforgeeks.org/memory-layout-of-c-program/ )।

जब आप अभी शुरुआत कर रहे हैं, तब "rvalue" शब्द अपारदर्शी लग सकता है, इसलिए मुझे आशा है कि निम्नलिखित इसके बारे में एक अंतर्ज्ञान विकसित करने में मदद करता है।

Lvalue / rvalue एक समान चिन्ह (असाइनमेंट ऑपरेटर) के विभिन्न पक्षों के बारे में बात कर रहे हैं: lvalue = बाएँ हाथ की ओर (लोअरकेस L, न कि "एक") rvalue = दाएँ हाथ की ओर

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

x = y * 3

असेंबली स्यूडोकोड में यह कुछ इस खिलौने के उदाहरण की तरह लग सकता है :

load register A with the value at memory address y
load register B with a value of 3
multiply register A and B, saving the result in A
write register A to memory address x

++ ऑपरेटर (और इसके समकक्ष) को संशोधित करने के लिए "कहीं" की आवश्यकता है, अनिवार्य रूप से कुछ भी जो एक अंतराल के रूप में काम कर सकता है।

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

एक तरफ के रूप में: ++ निर्देश 1969 के आसपास रहा है (हालांकि यह सी के पूर्ववर्ती, बी में शुरू हुआ):

(केन थॉम्पसन का) अवलोकन (था) कि ++ x का अनुवाद x = x + 1 की तुलना में छोटा था। "

उस विकिपीडिया संदर्भ के बाद आपको सी भाषा के इतिहास पर डेनिस रिची ("के एंड आर सी" में "आर" द्वारा एक दिलचस्प राइटअप में ले जाया जाएगा, यहाँ सुविधा के लिए लिंक किया गया है: http://www.bell-labs.com/ usr / dmr / www / chist.html जहाँ आप "++" खोज सकते हैं।


6

कारण यह है कि मानक को ऑपरेंड की आवश्यकता होती है। अभिव्यक्ति (a+b)एक अंतराल नहीं है, इसलिए वेतन वृद्धि ऑपरेटर को लागू करने की अनुमति नहीं है।

अब, कोई यह कह सकता है कि "ठीक है, यह वास्तव में कारण है, लेकिन वास्तव में इसके अलावा कोई * वास्तविक * कारण नहीं है" , लेकिन अनजाने में विशेष रूप से कैसे काम करता है कि ऑपरेटर तथ्यात्मक रूप से काम करता है, इस मामले की आवश्यकता है।

अभिव्यक्ति ++ ई के बराबर (ई + = 1) है।

जाहिर है, आप नहीं लिख सकते हैं E += 1अगर Eएक अंतराल नहीं है। जो एक शर्म की बात है क्योंकि कोई भी बस इतना ही कह सकता है: "ई द्वारा वेतन वृद्धि" और किया जाए। उस मामले में, संचालक को गैर-लैवल्यू पर लागू करना (सिद्धांत रूप में) कंपाइलर को थोड़ा अधिक जटिल बनाने की कीमत पर पूरी तरह से संभव होगा।

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

यदि आप सी के अलावा C ++ पर विचार करते हैं (प्रश्न C को टैग किया गया है, लेकिन ऑपरेटर अधिभार के बारे में चर्चा थी), तो कहानी और अधिक जटिल हो जाती है। सी में, यह कल्पना करना मुश्किल है कि यह मामला हो सकता है, लेकिन सी ++ में परिणाम (a+b)बहुत अच्छी तरह से हो सकता है कि आप बिल्कुल भी वेतन वृद्धि नहीं कर सकते हैं, या वेतन वृद्धि के काफी दुष्प्रभाव हो सकते हैं (केवल 1 को जोड़कर नहीं)। संकलक को उस के साथ सामना करने में सक्षम होना चाहिए, और समस्याग्रस्त मामलों का निदान करना चाहिए क्योंकि वे होते हैं। एक अंतराल पर, यह अभी भी जांच करने के लिए थोड़े तुच्छ है। किसी कोष्ठक के अंदर किसी भी तरह की बेतुकी अभिव्यक्ति के लिए ऐसा नहीं है जिसे आप घटिया चीज पर फेंकते हैं।
यह एक वास्तविक कारण नहीं है कि यह क्यों नहीं हो सका किया जा सकता है, लेकिन यह सुनिश्चित करता है कि एक स्पष्टीकरण के रूप में उधार दिया जाता है कि जिन लोगों ने इसे लागू किया है, वे इस तरह की सुविधा को जोड़ने के लिए सटीक रूप से उदार नहीं हैं जो बहुत कम लोगों को बहुत कम लाभ का वादा करता है।



3

++ मूल चर को मान देने की कोशिश करता है और चूंकि (ए + बी) एक अस्थायी मूल्य है जो ऑपरेशन नहीं कर सकता है। और वे मूल रूप से प्रोग्रामिंग को आसान बनाने के लिए C प्रोग्रामिंग सम्मेलनों के नियम हैं। बस।


2

जब ++ (+ a + b) एक्सप्रेशन किया जाता है, तो उदाहरण के लिए:

int a, b;
a = 10;
b = 20;
/* NOTE :
 //step 1: expression need to solve first to perform ++ operation over operand
   ++ ( exp );
// in your case 
   ++ ( 10 + 20 );
// step 2: result of that inc by one 
   ++ ( 30 );
// here, you're applying ++ operator over constant value and it's invalid use of ++ operator 
*/
++(a+b);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.