2010-02-01 12 views
7

के साथ सी में एक संरचना को परिभाषित करना मैंने मैलोक का उपयोग करके संरचना को परिभाषित करने पर question earlier से पूछा। इस उत्तर मैं बहुमत द्वारा दिया गया था था:मॉलोक

struct retValue* st = malloc(sizeof(*st)); 

मैं एक दोस्त मेरी कोड दिखाया जा रहा था, और हम एक बड़ी बाधा के लिए आया था। क्या कोई यह बता सकता है कि यह कोड क्यों काम करता है? मेरे दृष्टिकोण से, * जब आप इसे मॉल करते हैं, तो सेंट को परिभाषित नहीं किया गया है, इसलिए वहां किसी भी तरह का कचरा हो सकता है। यह होना चाहिए malloc(sizeof(struct retValue))

किसी भी मदद

+0

आपने अपने प्रश्न का उत्तर दिया। आकार (संरचना retValue) सही है –

+1

क्षमा करें, सवाल यह नहीं था कि 'क्या यह सही है, या सही क्या है?' यह 'यह क्यों काम करता है?' – Blackbinary

+2

यदि आप शब्दावली को बदलते हैं तो यह समझने में सहायता कर सकता है। आप malloc का उपयोग कर * एक संरचना * परिभाषित नहीं कर रहे हैं, आप * malloc का उपयोग कर * एक संरचना * आवंटित कर रहे हैं। आप 'st' को परिभाषित कर रहे हैं, जो एक सूचक (संरचना नहीं है) है। वह पॉइंटर पहले से परिभाषित है और प्रारंभिक अभिव्यक्ति (बराबर चिह्न के आरएचएस पर) में उपयोग के लिए उपलब्ध है, इसका मूल्य नहीं है, इसलिए अधिकांश उपयोग अमान्य होंगे। यह ठीक है, हालांकि, क्योंकि आकार मूल्य का उपयोग नहीं करता है। –

उत्तर

19

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

आपके उदाहरण में, सेंट को पहले ही पॉइंटर-टू-स्ट्रक्चर-रेटवैल्यू के रूप में घोषित किया गया है। नतीजतन संकलक "* सेंट" अभिव्यक्ति के प्रकार को कम करने में सक्षम है।

हालांकि ऐसा लगता है कि यह आपके कोड में पहले ही घोषित नहीं है, संकलक पहले से ही आपके लिए इसका ख्याल रख चुका है। आपके कोड में सभी घोषणाओं को ब्लॉक की शुरुआत में स्थानांतरित किया जाता है जिसमें वे कंपाइलर द्वारा होते हैं। मान लीजिए कि आप

संकलक के लिए उपलब्ध ज्ञान को चित्रित करने का एक तरीका यह है कि यह उत्पन्न होने वाले मध्यवर्ती आउटपुट को देखना है। इस उदाहरण कोड पर विचार करें ...

struct retValue {long int a, long int b}; 
... 
printf("Hello World!\n"); 
struct retValue* st = malloc(sizeof(*st)); 

एक उदाहरण के रूप जीसीसी और मुख्य()test.c के समारोह में तेह उपरोक्त कोड का उपयोग करना, की चलाकर मध्यवर्ती उत्पादन को देखो ...

gcc -fdump-tree-cfg test.c 

संकलक फ़ाइल उत्पन्न होगा test.c.022t.cfg - इसे देखो और आप देखेंगे

[ ... removed internal stuff ...] 
;; Function main (main) 

Merging blocks 2 and 3 
main (argc, argv) 
{ 
    struct retValue * st; 
    int D.3097; 
    void * D.3096; 

    # BLOCK 2 
    # PRED: ENTRY (fallthru) 
    __builtin_puts (&"Hello World!"[0]); 
    D.3096 = malloc (16); 
    st = (struct retValue *) D.3096; 
    D.3097 = 0; 
    return D.3097; 
    # SUCC: EXIT 

} 

नोट करें कि घोषणा को ब्लॉक की शुरुआत में कैसे स्थानांतरित किया गया था और मॉलोक के लिए तर्क पहले ही वास्तविक मूल्य के साथ प्रतिस्थापित किया गया है जिस प्रकार अभिव्यक्ति का मूल्यांकन किया गया है। जैसा कि टिप्पणियों में बताया गया है, तथ्य यह है कि घोषणा ब्लॉक के शीर्ष पर ले जाया गया था संकलक का कार्यान्वयन विवरण है। हालांकि, तथ्य यह है कि संकलक ऐसा करने में सक्षम है और मॉलोक में सही आकार डालने के लिए सभी दिखाता है कि संकलक इनपुट से आवश्यक जानकारी को कम करने में सक्षम था।

मैं व्यक्तिगत रूप से आकार के पैरामीटर के रूप में वास्तविक प्रकार का नाम देना पसंद करता हूं, लेकिन शायद यह कोडिंग-शैली का सवाल है जहां मैं कहूंगा कि स्थिरता व्यक्तिगत प्राथमिकता को रोकती है।

+1

उनका प्रश्न '* st'" बुरी चीजें "करने के बारे में था। '* st' अमान्य है यदि' st' मान्य डेटा को इंगित नहीं करता है। लेकिन चूंकि 'sizeof' अपने तर्क का मूल्यांकन नहीं करता है, इसलिए '* st' को' आकार 'के लिए एक ऑपरेंड के रूप में उपयोग करना ठीक है, भले ही' st' 'NULL' उदाहरण के लिए हो। –

+0

दरअसल, सवाल यह था कि "इस तथ्य के बावजूद यह कैसे काम करता है कि उस समय सेंट को आवंटित नहीं किया जा सकता है जब मॉलोक को आवंटित करने की आवश्यकता है" ... – VoidPointer

+1

पार्स में ब्लॉक की शुरुआत में एक घोषणा करना कोड का संस्करण एक कार्यान्वयन विस्तार है। कंपाइलर को ऐसा करने की आवश्यकता नहीं है, भले ही आपका होता है, और प्रश्नकर्ता का कोड काम करता है कि संकलक इसे करता है या नहीं। निम्नलिखित कोड संकलित नहीं करता है, यह दर्शाता है कि घोषणा "वास्तव में" नहीं चली गई है: 'sizeof (* st); चार * सेंट = 0; '। –

19

sizeof ऑपरेटर वास्तव में अपनी संकार्य का मूल्यांकन नहीं करता है के लिए धन्यवाद - यह सिर्फ अपने प्रकार पर लग रहा है। यह रनटाइम के बजाए संकलन समय पर किया जाता है। तो चर को आवंटित करने से पहले इसे सुरक्षित रूप से किया जा सकता है।

+0

मुझे लगता है कि मैं समझता हूं। तो आपकी कहानियां 'sizeof' * सेंट पर दिखती है और कहती है' ओह एक पॉइंटर है! ' और उसके बाद एक सूचक के लिए पर्याप्त स्मृति आवंटित करता है। यह परवाह नहीं करता कि * सेंट वास्तव में क्या हो रहा है। सही? – Blackbinary

+5

नहीं, यह दूसरी तरफ है। '* st' का अर्थ है" वह चीज़ जो बिंदुओं को इंगित करती है ", इसलिए संकलक संरचना का आकार देता है, न कि सूचक का आकार। –

+3

@ ब्लैकबिनरी: बंद करें: 'st' एक सूचक है, लेकिन' * st' एक संरचना है। तो यह '* st' पर दिखता है और कहता है" ओह यह एक 'ret retueue'' है! " और फिर एक retValue संरचना के लिए पर्याप्त स्मृति आवंटित करता है। '* St' की वास्तविक सामग्री कोई फर्क नहीं पड़ता। – interjay

1

संरचना प्रकार की घोषणा/परिभाषा क्या है और इस तरह के वर्ग की किसी वस्तु की परिभाषा नहीं है। जब तक आप malloc तक पहुंचते हैं, तो संकलक द्वारा एक घोषणा/परिभाषा का सामना किया जाएगा, आप अन्यथा एक कंपाइलर त्रुटि हिट करेंगे।

तथ्य यह है कि sizeof अपने ऑपरेटरों का मूल्यांकन नहीं करता है एक पक्ष-मुद्दा है।

एक छोटी सी निट: याद है कि हम कोष्ठकों जरूरत जब हम में के रूप में sizeof के प्रकार के नाम की आपूर्ति: वस्तुओं के मामले में

sizeof(struct retValue); 

और नहीं, हम बस कार्य करें:

sizeof *st; 

मानक देखें:

6.5 .3 एकल ऑपरेटरों सिंटेक्स

unary-expression: 
[...] 
sizeof unary-expression 
sizeof (type-name) 
0

सी में, sizeof एक ऑपरेटर है, और उसके तर्क का मूल्यांकन नहीं करता है। इससे "रोचक" प्रभाव हो सकते हैं, कि सी के लिए कोई नया जरूरी नहीं है। मैंने उल्लेख किया कि my answer में "अजीब भाषा सुविधा" प्रश्न में अधिक विस्तार से।

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