2010-06-20 12 views
8

पर एक सूचक देता है। यहां एक साक्षात्कार प्रश्न है जिसे मैंने कुछ मंच पर देखा था। मैं यह पता लगाने की कोशिश कर रहा हूं कि यह कैसे काम करता है लेकिन मुझे काफी कुछ नहीं मिलता है। क्या कोई समझा सकता है कि यह कैसे काम करता है?एक संरचना के भीतर सदस्य के लिए एक सूचक को देखते हुए, एक दिनचर्या लिखें जो संरचना

प्रश्न: एक संरचना के भीतर सदस्य के लिए एक सूचक को देखते हुए, एक दिनचर्या लिखें जो संरचना के लिए एक सूचक देता है।

struct s 
{ 
    ... 
    int a; 
    … 
}; 

struct s *get_s_ptr(int *a_ptr) 
{ 
    // implement this. 
} 

जवाब है:

struct s* get_s_ptr(int *a_ptr) 
{ 
    return (struct s*)((char*)a_ptr - (int)&((struct s*)0)->a); 
} 
+0

क्या **क्या आप पूछ रहे हो? –

+0

क्षमा करें, मेरे पास शीर्षक में सवाल था लेकिन पोस्ट ही नहीं। यह अभी तय है। – Steve

उत्तर

12

यह कैसे काम करता है?

मौलिक समीकरण यहाँ (बाइट्स में सभी गणित)

address of struct member s->a == s + byte offset of a 

है s के प्रकार, एक भी संकलक, और एक एकल लक्ष्य मशीन देखते हुए, वे बाइट a — की भरपाई निर्धारित यह है प्रकार की प्रत्येक संरचना के लिए समान है।

आपको बाईं तरफ दिया गया है और आपके साक्षात्कारकर्ता ने आपको s पुनर्प्राप्त करने के लिए कहा है। आप एक नया समीकरण प्राप्त करके ऐसा कर सकते हैं; बाइट दोनों पक्षों से ऑफसेट घटाना:

address of struct member s->a - byte offset of a == s 

समस्या में, आप दियाs->a का पता हो, लेकिन तुम बाइट ऑफसेट यह पता लगाने की है।

    : के रूप में

    struct pointer s where s is zero       (struct s *)0 
    struct member s->a where s is zero       ((struct s*)0)->a 
    address of s->a where s is zero        &((struct s*)0)->a 
    

    अंतिम चरण निम्न

    address of struct member s->a where s is zero == zero + byte offset of a 
                   == byte offset of a 
    

    सी में बाएं हाथ की ओर बनाया गया है ऐसा करने के लिए आप s सेट शून्य करने के लिए के साथ फिर से मूल समीकरण का उपयोग

  1. अंकगणित कानूनी सी बनाने के लिए इस बाइट ऑफ़सेट को पूर्णांक में डाला गया है।
  2. यह सुनिश्चित करने के लिए कि बाइट्स की इकाइयों में घटाव किया जाता है, a_ptrchar * पर डाला जाता है।
  3. परिणाम देने के लिए सही प्रकार का अंतर struct s * पर डाला गया है।

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

+0

असली अच्छा, स्पष्टीकरण! धन्यवाद –

+3

आपने कोड के एक बिल्कुल गलत, गैर मानक और आम तौर पर * खराब * टुकड़े का एक विस्तृत विस्तृत स्पष्टीकरण दिया। –

+1

@Eli: अच्छा बिंदु। मैंने अपना जवाब संपादित कर लिया है। –

4

आप मैक्रो offsetof उपयोग कर सकते हैं।

struct s* get_s_ptr(int *a_ptr) 
{ 
    return (struct s*)((char*)a_ptr - offsetof(struct s,a)); 
} 

मुझे देर हो चुकी है। मेरा इंटरनेट कनेक्शन धीमा है।

5

उत्तर है: यह नहीं है। यह काम नहीं करता है, भले ही यह पहली नजर में "काम" लग रहा हो। "उत्तर" एक शून्य सूचक को कम करने का प्रयास करता है, जो अपरिभाषित व्यवहार की ओर जाता है। इसलिए, जब तक कि "काम करने" के आपके विचार में अनिर्धारित व्यवहार शामिल नहीं है, वह उत्तर काम नहीं करता है।

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

गर्भित तकनीक का उचित कार्यान्वयन शामिल होगा मानक offsetof मैक्रो (पहले से ही न्यान के जवाब में सुझाव दिया है, लेकिन मैं इसे एक बार दोहराने की आवश्यकता होगी)

struct s* get_s_ptr(int *a_ptr) 
{ 
    return (struct s*) ((char *) a_ptr - offsetof(struct s, a)); 
} 
+0

'न्यूल' सूचक के बारे में सहमत हैं। सैद्धांतिक रूप से यह शून्य नहीं हो सकता है, यह शिकंजा चीजें हैं। हालांकि इस सूचक का कोई डिफ्रेंसिंग नहीं है। यदि आप 'ऑफ़सेट' की परिभाषा को देखते हैं - तो आप बिल्कुल वही चीज़ देखेंगे। वह है, लिखना और (pObj-> ए) कुछ भी अस्वीकार नहीं करता है। क्योंकि अभिव्यक्ति का परिणाम पता है। यह सिर्फ एक अंकगणित है – valdo

+1

और (पीओबीजे-> ए) और ((* पीओबीजे)। ए) जैसा ही है। इसलिए यदि पोब्ज नल है तो यह शून्य सूचक को अस्वीकार कर रहा है। – Nyan

+0

मैंने इसे यहां आजमाया: http://codepad.org/PtLv8XN7। ((संरचना एस *) 0) -> एक सीईजी गलती की ओर जाता है जबकि ((संरचना एस *) 0) -> सही ऑफसेट की ओर जाता है। कोई विचार? भले ही, ऑफसेट() शायद यह करने का सबसे अच्छा तरीका है। – Steve

1

सोचा यह मददगार होगा,

/* offsetof example */ 
#include <stdio.h> 
#include <stddef.h> 

struct mystruct { 
    char singlechar; 
    char arraymember[10]; 
    char anotherchar; 
}; 

int main() 
{ 
    printf ("offsetof(mystruct,singlechar) is %d\n",offsetof(mystruct,singlechar)); 
    printf ("offsetof(mystruct,arraymember) is %d\n",offsetof(mystruct,arraymember)); 
    printf ("offsetof(mystruct,anotherchar) is %d\n",offsetof(mystruct,anotherchar)); 

    return 0; 
} 

आउटपुट:

offsetof(mystruct,singlechar) is 0 
offsetof(mystruct,arraymember) is 1 
offsetof(mystruct,anotherchar) is 11 
अपने मामले में

तो,

return (struct s*) ((char *) a_ptr - offsetof(struct s, a)); 
  • aptr डाली char के लिए *
  • घटाना struct s
  • डाली struct s*
  • में लौटने a wrt की भरपाई resultant ptr
संबंधित मुद्दे