2011-10-26 14 views
8

संभव डुप्लिकेट:
Why does this C code work?
How do you use offsetof() on a struct?सी ऑफसेट मैक्रो कैसे काम करता है?

मैं इस इंटरनेट पर मैक्रो offsetof के बारे में पढ़ा है, लेकिन यह स्पष्ट नहीं होता कि क्या इसके लिए प्रयोग किया जाता है।

#define offsetof(a,b) ((int)(&(((a*)(0))->b))) 

ऐसा करने का प्रयास क्या है और इसका उपयोग करने का क्या फायदा है?

+2

कि 'मैक्रो offsetof' सही नहीं है। उन्हें 'size_t' पर डाला जाना चाहिए, न कि 'int', और संभवतः उन्हें नल सूचकांक स्थिर होने के बावजूद परिणाम से' (char *) 0' घटा देना चाहिए। –

उत्तर

12

इसका कोई लाभ नहीं है और इसका उपयोग नहीं किया जाना चाहिए, क्योंकि यह अपरिभाषित व्यवहार का आह्वान करता है (और size_t के बजाय गलत प्रकार - int का उपयोग करता है)।

#include <stddef.h> 

struct foo { 
    int a; 
    int b; 
    char *c; 
}; 

struct struct_desc { 
    const char *name; 
    int type; 
    size_t off; 
}; 

static const struct struct_desc foo_desc[] = { 
    { "a", INT, offsetof(struct foo, a) }, 
    { "b", INT, offsetof(struct foo, b) }, 
    { "c", CHARPTR, offsetof(struct foo, c) }, 
}; 

जो दिया जाएगा आप प्रोग्राम के क्षेत्र को भरने:

सी मानक stddef.h में एक offsetof मैक्रो जो वास्तव में, काम करता है जैसे मामलों में जहां आपको बस एक संरचना में एक तत्व की भरपाई, के लिए परिभाषित करता है नाम से struct foo, उदाहरण के लिए एक JSON फ़ाइल पढ़ते समय।

+0

मुझे खेद है - ऑफसेट ऑफ मैक्रो कारण अपरिभाषित व्यवहार कैसे करता है खासकर जब से इसे सी मानक में परिभाषित किया गया था? –

+3

'stddef.h' से मानक 'ऑफ़सेटफ़ोफ़' मैक्रो यूबी का आह्वान नहीं करता है। ऑफ़सेट की गणना करने के लिए अपने स्वयं के हैक को परिभाषित करना इस तरह से यूबी का आह्वान करता है। –

+0

कृपया मुझे मानक संदर्भ उद्धृत करें जो मैक्रो के अपने संस्करण को परिभाषित करता है, अपरिभाषित व्यवहार –

4

यह struct के किसी विशेष सदस्य के बाइट ऑफसेट को ढूंढ रहा है। उदाहरण के लिए, यदि आप निम्न संरचना था:

struct MyStruct 
{ 
    double d; 
    int i; 
    void *p; 
}; 

तो फिर तुम offsetOf(MyStruct, d) == 0, offsetOf(MyStruct, i) == 8, और offsetOf(MyStruct, p) == 12 होगा (जो है, सदस्य d नामित संरचना, आदि की शुरुआत से 0 बाइट्स की है)।

जिस तरह से यह काम करता है यह दिखाता है कि आपकी संरचना का एक उदाहरण पता 0 (((a*)(0)) भाग) पर मौजूद है, और फिर यह इच्छित संरचना सदस्य का पता लेता है और इसे पूर्णांक में रखता है। हालांकि पता 0 पर किसी ऑब्जेक्ट को डिफ्रेंस करना सामान्य रूप से एक त्रुटि होगी, तो पता लगाना ठीक है क्योंकि ऑपरेटर का पता & और सदस्य dereference -> एक-दूसरे को रद्द कर देता है।

यह आमतौर पर सामान्यीकृत क्रमबद्धता फ्रेमवर्क के लिए उपयोग किया जाता है। यदि आपके पास किसी प्रकार के वायर डेटा (जैसे फाइल में या नेटवर्क से बाइट्स) और इन-मेमोरी डेटा स्ट्रक्चर के बीच कनवर्ट करने के लिए कोड है, तो सदस्य नाम से सदस्य ऑफ़सेट में मैपिंग बनाना अक्सर सुविधाजनक होता है, ताकि आप क्रमबद्ध कर सकें या एक सामान्य तरीके से मूल्यों को deserialize।

+0

प्रश्न सी है, हमें अभी भी 'संरचना MyStruct' का उपयोग करना होगा। ;) –

24

आर .. आपके प्रश्न के दूसरे भाग के जवाब में सही है: आधुनिक सी कंपाइलर का उपयोग करते समय इस कोड की सलाह नहीं दी जाती है।

अपने प्रश्न के पहले भाग का जवाब देने की लेकिन, क्या यह वास्तव में कर रहा है:

(
    (int)(  // 4. 
    &((  // 3. 
     (a*)(0) // 1. 
    )->b)  // 2. 
) 
) 

अंदर बाहर से काम करते हुए, यह है ...

  1. struct सूचक प्रकार a*
  2. को मान शून्य कास्टिंग हो रही है इस बात का struct क्षेत्र ख (अवैध रूप से रखा) struct वस्तु
  3. एक को पता कास्टिंग इस b क्षेत्र
  4. का पता हो रही है int

वैचारिक इस स्मृति पते के शून्य पर एक struct वस्तु डाल रहा है और उसके बाद क्या एक particul के पते पर यह जानने आर क्षेत्र है। यह आपको संरचना में प्रत्येक फ़ील्ड की स्मृति में ऑफ़सेट को समझने की अनुमति दे सकता है ताकि आप अपने स्वयं के धारावाहिक और deserializers लिख सकें और बाइट एरे से structs को परिवर्तित करने के लिए।

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

सी int के आकार पर चलने वाले अधिकांश मूल सिस्टम 32 बिट्स थे और यह सूचक के समान था, इसलिए यह वास्तव में काम करता था।

-2

ऑफ़सेट मैक्रो का कार्यान्वयन वास्तव में अप्रासंगिक है।

वास्तविक सी मानक 7.17.3 में के रूप में यह परिभाषित करता है:

offsetof(type, member-designator) 

जो टाइप size_t है कि एक पूर्णांक निरंतर अभिव्यक्ति के लिए विस्तारित, जिसका मूल्य बाइट में ऑफसेट, (है संरचना सदस्य के लिए सदस्य-डिजाइनर द्वारा नामित), इसकी संरचना की शुरुआत से (प्रकार द्वारा निर्दिष्ट)। प्रकार और सदस्य डिज़ाइनर ऐसा होगा कि static type t; दिया गया।

ट्रस्ट एडम रोसेनफील्ड का जवाब।

आर पूरी तरह से गलत है, और इसमें कई उपयोग हैं - विशेष रूप से यह बताने में सक्षम होना कि प्लेटफॉर्म के बीच कोड गैर-पोर्टेबल है।

(ठीक है, यह सी ++ है, लेकिन हम स्थिर टेम्पलेट में इसका इस्तेमाल करते हैं यकीन है कि हमारे डेटा संरचनाओं प्लेटफार्मों/संस्करणों के बीच आकार में परिवर्तन नहीं करते बनाने के लिए समय दावे संकलन।)

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