2008-12-30 13 views

उत्तर

8

यह जीसीसी संकलक द्वारा प्रदान की अंतर्निहित offsetof मैक्रो C और C++ मानक द्वारा निर्दिष्ट किया जाता लागू करने के लिए है:

GCC - offsetof

यह बाइट में ऑफसेट रिटर्न कि एक पॉड struct के एक सदस्य/संघ में है

नमूना:

struct abc1 { int a, b, c; }; 
union abc2 { int a, b, c; }; 
struct abc3 { abc3() { } int a, b, c; }; // non-POD 
union abc4 { abc4() { } int a, b, c; }; // non-POD 

assert(offsetof(abc1, a) == 0); // always, because there's no padding before a. 
assert(offsetof(abc1, b) == 4); // here, on my system 
assert(offsetof(abc2, a) == offsetof(abc2, b)); // (members overlap) 
assert(offsetof(abc3, c) == 8); // undefined behavior. GCC outputs warnings 
assert(offsetof(abc4, a) == 0); // undefined behavior. GCC outputs warnings 

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

+0

मुझे लगता है कि यह उपयोगी था कि घुसपैठ किए गए नोड्स में "अगली" ऑब्जेक्ट में नोड को पॉइंटर्स होते हैं। सूची का उपयोग करते समय, आपको ऑब्जेक्ट के आधार पर नोड से प्राप्त करने की आवश्यकता होती है, इसलिए आप पॉइंटर मान और reinterpret_cast से ऑफसेट (कुछ) बाइट घटाते हैं। –

+0

सी ++ में सभी बहुत ही पोर्टेबल, निश्चित रूप से, लेकिन सी –

2

@litb के रूप में, ने कहा: एक संरचना/वर्ग सदस्य के बाइट्स में ऑफसेट। सी ++ में ऐसे मामले हैं जहां यह अनिर्धारित है, यदि संकलक शिकायत करेगा। IIRC, एक तरह से इसे लागू करने के लिए (सी में, कम से कम)

#define offsetof(type, member) (int)(&((type *)0)->member) 

करना है लेकिन मुझे यकीन है कि इस समस्या नहीं हैं, लेकिन मैं कोई दिलचस्पी पाठक के लिए कि छोड़ देंगे बताते ...

+0

में काम करता है, सी में भी अपरिभाषित व्यवहार, कई कारणों से, यहां तक ​​कि: एक स्टडी मैक्रो को फिर से परिभाषित करना और न्यूल का डेफ्रफ़ करना। हालांकि, stdlib में आम है, क्योंकि यह विभिन्न नियमों से बंधे हैं। – MSalters

+0

@MSalters - जेस्पर सही है। लिनक्स कर्नेल स्रोत कोड में stddef.h में परिभाषा देखें: http://lxr.linux.no/#linux+v2.6.31/include/linux/stddef.h#L24 –

12

@litb बताते हैं और @ जेस्पर शो दिखाता है, ऑफसेट() बाइट्स में एक पूर्णांक ऑफसेट प्रदान करता है (size_t मान के रूप में)।

आप इसका उपयोग कब कर सकते हैं?

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

#include <stddef.h> 

typedef stuct config_info config_info; 
struct config_info 
{ 
    int parameter1; 
    int parameter2; 
    int parameter3; 
    char *string1; 
    char *string2; 
    char *string3; 
    int parameter4; 
} main_configuration; 

typedef struct config_desc config_desc; 
static const struct config_desc 
{ 
    char *name; 
    enum paramtype { PT_INT, PT_STR } type; 
    size_t offset; 
    int min_val; 
    int max_val; 
    int max_len; 
} desc_configuration[] = 
{ 
    { "GIZMOTRON_RATING", PT_INT, offsetof(config_info, parameter1), 0, 100, 0 }, 
    { "NECROSIS_FACTOR", PT_INT, offsetof(config_info, parameter2), -20, +20, 0 }, 
    { "GILLYWEED_LEAVES", PT_INT, offsetof(config_info, parameter3), 1, 3, 0 }, 
    { "INFLATION_FACTOR", PT_INT, offsetof(config_info, parameter4), 1000, 10000, 0 }, 
    { "EXTRA_CONFIG",  PT_STR, offsetof(config_info, string1), 0, 0, 64 }, 
    { "USER_NAME",  PT_STR, offsetof(config_info, string2), 0, 0, 16 }, 
    { "GIZMOTRON_LABEL", PT_STR, offsetof(config_info, string3), 0, 0, 32 }, 
}; 

अब आप एक सामान्य फ़ंक्शन लिख सकते हैं जो कॉन्फ़िगरेशन फ़ाइल से लाइनें पढ़ता है, टिप्पणियां और रिक्त रेखाओं को छोड़ देता है। यह पैरामीटर नाम को अलग करता है, और यह देखता है कि desc_configuration तालिका में (जिसे आप सॉर्ट कर सकते हैं ताकि आप बाइनरी खोज कर सकें - एकाधिक SO प्रश्न पता)। जब यह सही config_desc रिकॉर्ड पाता है, तो यह उस मान को पार कर सकता है और config_desc दो दिनचर्या में से एक में प्रवेश - एक स्ट्रिंग को प्रोसेस करने के लिए, दूसरा पूर्णांक प्रोसेसिंग के लिए।

उन कार्यों का महत्वपूर्ण हिस्सा है:

static int validate_set_int_config(const config_desc *desc, char *value) 
{ 
    int *data = (int *)((char *)&main_configuration + desc->offset); 
    ... 
    *data = atoi(value); 
    ... 
} 

static int validate_set_str_config(const config_desc *desc, char *value) 
{ 
    char **data = (char **)((char *)&main_configuration + desc->offset); 
    ... 
    *data = strdup(value); 
    ... 
} 

इस संरचना के प्रत्येक अलग सदस्य के लिए एक अलग समारोह में लिखने के लिए होने टाल।

+1

यदि आप वास्तव में बुराई प्राप्त करना चाहते हैं 'desc_configuration' में पैरामीटर नाम और अनुक्रमणिका वाले एक हैश तालिका का उपयोग कर सकते हैं। रास्ते से वास्तव में अद्भुत उदाहरण। –

+1

@Robert: यह उदाहरण कॉन्फ़िगरेशन फ़ाइल से डेटा को एक बड़ी डेटा संरचना में पढ़ने और प्रक्रिया को उलट करने पर आधारित है। मैं यह बताने के लिए परेशान नहीं होगा कि यह वर्तमान में कैसे किया जाता है: कहने के लिए पर्याप्त है, 300 पैरामीटर हैं, फ़ंक्शन में कोड की लगभग 4500 लाइनें जो इसे सब संभालती हैं, और बहुत बार दोहराई जाती हैं। मैं कोड का प्रभारी नहीं हूं - दुख की बात है। –

+0

यह भी देखें: http://stackoverflow.com/questions/1445762/need-way-to-alter-common-fields-in- अलग- संरचनाएं –

7

अंतर्निहित __offsetof ऑपरेटर का उद्देश्य यह है कि संकलक विक्रेता # ऑफसेट() मैक्रो को परिभाषित कर सकता है, फिर भी यह कक्षाओं के साथ काम करता है जो यूनरी ऑपरेटर & को परिभाषित करता है। Offsetof() की सामान्य सी मैक्रो परिभाषा केवल तभी काम करती है जब (& lvalue) उस रावल के पते को वापस कर दिया। अर्थात।

#define offsetof(type, member) (int)(&((type *)0)->member) // C definition, not C++ 
struct CFoo { 
    struct Evil { 
     int operator&() { return 42; } 
    }; 
    Evil foo; 
}; 
ptrdiff_t t = offsetof(CFoo, foo); // Would call Evil::operator& and return 42 
संबंधित मुद्दे