2010-05-26 13 views
16

मैं हमेशा यह जानना चाहता था कि संकलक एक संरचना (सी अनुमान में) और एक संरचना के लिए सूचक को कैसे देखते हैं, इस बारे में वास्तविक बात क्या है।"->" और "।" के बारे में असली चीज़

struct person p; 
struct person *pp; 

pp->age, मैं हमेशा कल्पना करो कि संकलक करता है: "पीपी का मूल्य + गुण की भरपाई" उम्र "struct में"।

लेकिन यह person.p के साथ क्या करता है? यह लगभग वही होगा। मेरे लिए "प्रोग्रामर", पी एक स्मृति पता नहीं है, इसकी तरह "संरचना स्वयं" है, लेकिन निश्चित रूप से यह नहीं है कि संकलक इसके साथ कैसे निपटता है।

मेरा अनुमान है कि यह एक वाक्य रचनात्मक चीज है, और संकलक हमेशा (&p)->age करता है।

मैं सही हूँ?

+1

प्रश्न को हाइजैक नहीं करना है, लेकिन एक छात्र के रूप में मैं उत्सुक हूं कि इस क्षेत्र की चीज़ किस प्रकार से सीखती है। कंपाइलर डिजाइन? (मेरा मतलब है, जाहिर है मैंने सीखा (* पी) .q मेरे सी ++ वर्ग में पी-> क्यू जैसा ही है) – Adam

+0

आमतौर पर एक निम्न-स्तरीय कंप्यूटर सिस्टम कोर्स (वह प्रकार जो स्मृति आवंटन, स्टैक फ्रेम, et cetera से संबंधित है) । – Amber

+0

धन्यवाद - मैं केवल एक सोफोरोर हूं इसलिए मुझे यकीन है कि हम अंततः – Adam

उत्तर

28

p->q अनिवार्य रूप से वाक्यात्मक चीनी कि में (*p).q के लिए यह सूचक p dereferences और फिर इसे भीतर उचित क्षेत्र q को जाता है। यह एक बहुत ही सामान्य मामले (structs के लिए पॉइंटर्स) के लिए टाइपिंग बचाता है।

संक्षेप में, ->दो deferences (संकेतक भिन्नता, क्षेत्र भिन्नता), जबकि . केवल एक (क्षेत्र भिन्नता) करता है।

एकाधिक-डीरेंसेंस कारक के कारण, -> को संकलक द्वारा स्थिर पते के साथ पूरी तरह से प्रतिस्थापित नहीं किया जा सकता है और इसमें हमेशा कम से कम पता गणना शामिल होगी (पॉइंटर्स रनटाइम पर गतिशील रूप से बदल सकते हैं, इस प्रकार स्थान भी बदल जाएंगे), जबकि कुछ मामलों में, . संचालन को संकलक द्वारा एक निश्चित पते तक पहुंच के साथ प्रतिस्थापित किया जा सकता है (क्योंकि आधार संरचना का पता भी ठीक किया जा सकता है)।

+1

"वाक्य रचनात्मक चीनी" (और एक अच्छी व्याख्या) के लिए +1 – Adam

+0

ठीक है। लेकिन मेरा सवाल यह है कि कंपाइलर के लिए बिल्कुल "पी" क्या है ?, यह भी एक पता है, है ना? लेकिन मेरे लिए प्रोग्रामर "संरचना खुद" है – fsdfa

+0

मान लीजिए 'पी' एक स्थानीय चर है, यह ढेर के भीतर एक ऑफसेट है। – Amber

5

अपडेट किया गया (टिप्पणी देखें):

आप सही पता नहीं है, लेकिन वहाँ वैश्विक और स्थैतिक चर के लिए एक महत्वपूर्ण अंतर केवल है: जब संकलक एक वैश्विक या स्थिर चर के लिए p.age देखता है , यह संरचना के भीतर age फ़ील्ड के सटीक पते के साथ संकलित समय पर इसे प्रतिस्थापित कर सकता है।

इसके विपरीत, pp->age के रूप में संकलित "पीपी का मूल्य + age क्षेत्र की भरपाई", के बाद से पीपी का मूल्य कार्यावधि में बदल सकते हैं किया जाना चाहिए।

+2

यदि इसे स्टैक पर घोषित किया गया है तो यह संकलन समय पर सटीक पता नहीं जानता है, केवल स्टैक पॉइंटर के खिलाफ ऑफ़सेट। – cjg

+0

जब यह p.age देखता है तो यह ** ऑफसेट ** को संरचना के भीतर जानता है, लेकिन नहीं (जब तक कि यह वैश्विक चर नहीं है) संरचना के पूर्ण पते को जानता है। – ChrisW

+0

@cjg और @ChrisW: अच्छे अंक। मैं अपना जवाब समायोजित करूंगा। –

1

चूंकि पी एक स्थानीय (स्वचालित) चर है, यह ढेर में संग्रहीत है। इसलिए संकलक स्टैक पॉइंटर (एसपी) या फ्रेम पॉइंटर (एफपी या बीपी, आर्किटेक्चर में जहां यह मौजूद है) के संबंध में ऑफ़सेट के मामले में इसका उपयोग करता है। इसके विपरीत, * पी ढेर में आवंटित स्मृति स्मृति [आमतौर पर] को संदर्भित करता है, इसलिए स्टैक रजिस्टरों का उपयोग नहीं किया जाता है।

+1

आप एक सबराउटिन को पते से एक स्टैक-आवंटित संरचना पास कर सकते हैं: इस मामले में सबराउटिन द्वारा प्राप्त पॉइंटर स्टैक पर एक ऑब्जेक्ट होता है। – ChrisW

+0

@ChrisW: अच्छा बिंदु। बेशक, संकलक अभी भी एक सीधा पता (एसपी का उपयोग किए बिना) के रूप में संरचना का उपयोग करता है। –

3

दो कथन "कंपाइलर परिप्रेक्ष्य" से भी समकक्ष नहीं हैं। बयान p.age, p का पता age की भरपाई + करने के लिए अनुवाद pp->age पता pp में निहित age की भरपाई + करने के लिए अनुवाद है।

पता एक चर और पता एक (सूचक) चर में निहित बहुत अलग बातें हैं।

तो p.age संदर्भ को संबोधित 105.

लेकिन अगर pp एक संरचना करने के लिए एक सूचक है, इसका पता 100 हो सकता है, कहते हैं कि उम्र के ऑफसेट 5. है p एक संरचना है, इसका पता 100 हो सकता है, लेकिन पता 100 पर संग्रहीत मूल्य person संरचना की शुरुआत नहीं है, यह एक सूचक है। तो पता 100 (पता pp में निहित) पर मूल्य हो सकता है, उदाहरण के लिए, 250 उस मामले में, pp->age संदर्भ को संबोधित 255, नहीं 105.

+0

दूसरे शब्दों में, 'p.age' से पढ़ने के लिए अवधारणात्मक रूप से' पी 'के (ज्ञात) स्थान से' आयु 'के ऑफसेट से, एक स्मृति पढ़ने की आवश्यकता होती है। जबकि 'पीपी-> आयु' से पढ़ने के लिए अवधारणा के लिए दो स्मृति पढ़ने की आवश्यकता होती है - एक 'पीपी' के स्थान से, फिर पहले पढ़ने और' आयु 'के ऑफसेट द्वारा दिए गए स्थान से दूसरा। – caf

0

दोनों ही मामलों में संरचना और उसके सदस्यों द्वारा संबोधित कर रहे हैं

पते (व्यक्ति) + ऑफसेट (उम्र)

एक struct ढेर स्मृति में संग्रहीत के साथ पी का उपयोग संकलक और अधिक विकल्प स्मृति के उपयोग का अनुकूलन करने देता है। यह केवल पूरे स्ट्रक्चर के बजाय उम्र को स्टोर कर सकता है, अगर कुछ भी नहीं उपयोग किया जाता है - यह उपर्युक्त फ़ंक्शन के साथ संबोधित करता है (मुझे लगता है कि एक स्ट्रक्चर का पता पढ़ना इस अनुकूलन को रोकता है)।
ढेर पर एक संरचना में कोई स्मृति पता नहीं हो सकता है। यदि संरचना पर्याप्त छोटा है और केवल थोड़ी देर तक रहता है तो इसे प्रोसेसर रजिस्टरों में से कुछ के लिए मैप किया जा सकता है (जैसा कि पते को पढ़ने के लिए उपरोक्त अनुकूलन के लिए)।

संक्षिप्त उत्तर: जब संकलक अनुकूलित नहीं करता है तो आप सही हैं। जैसे ही संकलक केवल सी मानक विनिर्देशों को अनुकूलित करता है, की गारंटी देता है।

संपादित करें: "पीपी->" के लिए त्रुटिपूर्ण स्टैक/ढेर स्थान हटा दिया गया है क्योंकि संरचना की ओर इशारा ढेर और ढेर दोनों पर हो सकता है।

+0

चर के स्थान पर पहुंचने के लिए उपयोग किए जाने वाले एड्रेसिंग मोड के साथ * कुछ नहीं * है। 'पीपी->' संरचना के साथ कहीं भी, ढेर, ढेर, "वैश्विक" हो सकता है। 'पी' के साथ संरचना ढेर मेमोरी को छोड़कर उपर्युक्त में से किसी भी में हो सकती है ('क्योंकि आप सीधे वहां चर घोषित नहीं कर सकते हैं)। मैं हमेशा पॉइंटर्स को तीरों की तरह सोचना पसंद करता हूं, जो स्मृति कोशिकाओं के सरणी को इंगित करता है। समानता के रूप में, यह आसान लगता है और इतना गलत नहीं है। –

+0

@ डोनल फैलो आप "पीपी->" के बारे में सही हैं, मैंने केवल सबसे सरल उपयोग के मामले के बारे में सोचा था। यदि उम्र एक संरचना थी तो आप इसे पीपी-> आयु.days के साथ संबोधित कर सकते हैं ताकि "।" स्मृति स्थान के बारे में ज्यादा कुछ नहीं कहता है। – josefx

+0

यह सच है। अंतर स्थान से संबंधित नहीं है, बल्कि इसके बजाय आपको किसी चीज का नाम मिला है (यानी, इसके लिए एक सूचक) या चीज स्वयं (मेमोरी सेल/स्ट्रक्चर/सरणी/...; कांटियन दर्शन में "डिंग ए sich ")। –

1

यह एक प्रश्न है जिसे मैंने हमेशा से पूछा है।

v.x, सदस्य ऑपरेटर, वैध केवल structs के लिए है। v->x, सूचक ऑपरेटर का सदस्य, केवल संरचना पॉइंटर्स के लिए वैध है।

तो दो अलग-अलग ऑपरेटरों क्यों हैं, क्योंकि केवल एक की आवश्यकता है? उदाहरण के लिए, केवल . ऑपरेटर का उपयोग किया जा सकता है; कंपाइलर हमेशा v के प्रकार को जानता है, इसलिए यह जानता है कि क्या करना है: v.x यदि v एक संरचना है, (*v).x यदि v एक संरचना सूचक है।गर्भाधान दिया

  • द्वारा कश्मीर & आर (जो सिद्धांत मैं झूठी होना चाहते हैं)
  • संकलक के लिए काम कर रही है आसान (एक व्यावहारिक सिद्धांत अस्थायी अदूरदर्शिता,:

    मैं तीन सिद्धांत है सी के समय :)

  • पठनीयता (जो सिद्धांत मैं पसंद)

दुर्भाग्य से, मैं नहीं जानता कि जो एक (यदि हो तो) सच है।

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