2009-09-21 14 views
7

में मैक्रो के ऑफ़सेट के कानूनी उपयोग सी/सी ++ में यह मैक्रो offsetof है जो आपको पीओडी संरचना में किसी सदस्य का पता ऑफसेट प्राप्त करने की अनुमति देता है। C FAQ से एक उदाहरण के लिए:सी/सी ++

struct foo { 
int a; 
int b; 
}; 

struct foo; 

/* Set the b member of foo indirectly */ 
*(int *)((char *)foo + offsetof(b)) = 0xDEADBEEF; 

अब यह सिर्फ मेरे लिए बुराई लगता है और मैं इस मैक्रो के कई कानूनी का उपयोग करता है नहीं देख सकता।

एक कानूनी उदाहरण मैंने देखा है यह एक एम्बेडेड संरचनाओं पैरेंट ऑब्जेक्ट का पता प्राप्त करने के लिए लिनक्स कर्नेल में container_of मैक्रो में फायदा नहीं है है:

/* get the address of the cmos device struct in which the cdev 
    structure which inode points to is embedded */ 
struct cmos_dev *cmos_devp = 
    container_of(inode->i_cdev, struct cmos_dev, cdev); 

क्या अन्य कानूनी का उपयोग करता है इस मैक्रो के लिए देखते हैं? आपको इस मैक्रो का उपयोग कब करना चाहिए?

EDIT अब तक this answer एक अलग SO प्रश्न के लिए सबसे अच्छा है जिसे मैंने अभी तक देखा है।

+0

आपका पहला उपयोग सी में वैध है, लेकिन सी ++ पॉइंटर्स-टू-सदस्य में बहुत अधिक आवश्यकता को हटा दें। –

+1

यहां इसके बारे में कुछ अन्य प्रश्न है: http://stackoverflow.com/questions/400116/what-is-the-purpose-and-return-type-of-the-builtinoffsetof-operator –

उत्तर

4

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

यह इस तरह काम करता है: विकल्प की आवश्यकता वाले कमांड को स्थानीय विकल्पों को अपने विकल्पों को धारण करने के लिए परिभाषित किया जाता है, और फिर उस संरचना को उस कोड में वर्णित करता है जो GUI उत्पन्न करता है, offsetof का उपयोग करके यह इंगित करता है कि फ़ील्ड कहां हैं। पूर्ण पते के बजाय ऑफ़सेट का उपयोग करने से जीयूआई कोड संरचना के किसी भी उदाहरण के साथ काम करने की अनुमति देता है, केवल एक ही नहीं।

यह एक उदाहरण (मैंने कोशिश की) में जल्दी से स्केच करना मुश्किल है, लेकिन चूंकि टिप्पणियां इंगित करती हैं कि एक उदाहरण क्रम में है, मैं फिर कोशिश करूंगा।

मान लें कि हमारे पास "कमांड" नामक एक स्व-निहित मॉड्यूल है, जो एप्लिकेशन में कुछ क्रिया लागू करता है। इस कमांड में विकल्पों का एक समूह है जो अपने सामान्य व्यवहार को नियंत्रित करता है, जिसे ग्राफ़िकल यूजर इंटरफेस के माध्यम से उपयोगकर्ता के सामने उजागर किया जाना चाहिए। इस उदाहरण के प्रयोजनों के लिए, मान लें कि एप्लिकेशन एक फ़ाइल प्रबंधक है, और कमांड उदाहरण हो सकता है "कॉपी"।

विचार यह है कि प्रतिलिपि कोड एक सी फ़ाइल में रहता है, और जीयूआई कोड दूसरे में रहता है, और जीयूआई कोड को कॉपी कमांड के विकल्पों को "समर्थन" करने के लिए हार्ड-कोड करने की आवश्यकता नहीं होती है। इसके बजाय, हम तो जैसे, प्रतिलिपि फ़ाइल में विकल्पों को परिभाषित:

struct copy_options 
{ 
    unsigned int buffer_size;  /* Number of bytes to read/write at a time. */ 
    unsigned int copy_attributes; /* Attempt to copy attributes. */ 
    /* more, omitted */ 
}; 

static struct copy_options options; /* Actual instance holding current values. */ 

फिर, प्रतिलिपि आदेश जीयूआई मॉड्यूल के साथ अपने विन्यास सेटिंग्स पंजीकृत करता है: तो फिर

void copy_register_options(GUIModule *gui) 
{ 
    gui_command_begin(gui, "Copy"); 
    gui_command_add_unsigned_int(gui, "Buffer size", offsetof(struct copy_options, buffer_size)); 
    gui_command_add_boolean(gui, "Copy attributes", offsetof(struct copy_options, copy_attributes)); 
    gui_command_end(gui); 
} 

, मान लें कि उपयोगकर्ता के लिए पूछता जाने कॉपी कमांड के विकल्प सेट करें। हम तो पहले मौजूदा विकल्पों कॉपी कर सकते हैं, उन्हें रद्द करने का समर्थन करने के लिए, और संपादन इस आदेश के विकल्प के लिए एक संवाद पकड़े नियंत्रण के लिए जीयूआई मॉड्यूल, रन-टाइम में बनाया गया है, उपयुक्त से पूछते हैं:

void copy_configure(GUIModule *gui) 
{ 
    struct copy_options edit = options; 

    /* Assume this opens a modal dialog, showing proper controls for editing the 
    * named command's options, at the address provided. The function returns 1 
    * if the user clicked "OK", 0 if the operation was cancelled. 
    */ 
    if(gui_config_dialog(gui, "Copy", &edit)) 
    { 
    /* GUI module changed values in here, make edit results new current. */ 
    options = edit; 
    } 
} 
बेशक

, इस कोड को मान लिया गया है सेटिंग्स शुद्ध मूल्य-प्रकार होने के लिए, इसलिए हम सरल संरचना असाइनमेंट का उपयोग करके संरचना की प्रतिलिपि बना सकते हैं। अगर हम गतिशील तारों का भी समर्थन करते हैं, तो हमें प्रतिलिपि करने के लिए एक फ़ंक्शन की आवश्यकता होगी। कॉन्फ़िगरेशन डेटा के लिए हालांकि, स्ट्रिंग में किसी भी स्ट्रिंग को सांख्यिकीय रूप से आकार के char सरणी के रूप में सबसे अच्छा व्यक्त किया जाएगा, जो ठीक होगा।

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

+0

केवल पॉइंटर का उपयोग नहीं करेगा आपको 'संरचना के किसी भी उदाहरण के साथ काम करने' की अनुमति भी देता है? –

+0

@Robert: क्योंकि यह केवल एक के साथ काम करेगा; जिसने इसे एक सूचक दिया है। ऑफ़सेट का उपयोग करके, आप जीयूआई-बिल्डिंग कोड में संरचना का पुन: वर्णन किए बिना, उसी संरचना के दो अलग-अलग उदाहरणों के लिए जीयूआई बना सकते हैं। – unwind

+0

मैं इसे किसी कारण से नहीं प्राप्त कर रहा हूं - क्या आप अपनी पोस्ट में एक संक्षिप्त कोड उदाहरण जोड़ सकते हैं? –

1

ऑफ़सेटफ़ोफ़ अक्सर डिवाइस ड्राइवर प्रोग्रामिंग के लिए उपयोग किया जाता है जहां आपको आमतौर पर सादे सी में लिखना होता है लेकिन कभी-कभी कुछ "अन्य" विशेषताओं की आवश्यकता होती है। मान लें कि आपके पास कॉलबैक फ़ंक्शन है जो कुछ संरचनाओं के लिए पॉइंटर प्राप्त करता है। अब यह संरचना स्वयं एक और बड़ी "बाहरी" संरचना का सदस्य है। "ऑफसेट" के साथ आपके पास "बाहरी" संरचना के सदस्यों को बदलने की क्षमता है जब आपके पास "आंतरिक" सदस्य को केवल तक पहुंच है।

कुछ इस तरह:

struct A 
{ 
int a1; 
int a2; 
}; 

struct B 
{ 
int b1; 
int b2; 
A a; 
}; 

void some_API_callback_func(A * a) 
{ 
//here you do offsetof 
//to get access to B members 
} 
बेशक

इस खतरनाक यदि आप इस संभावना है कि struct एक struct बी के हिस्से के रूप लेकिन कई स्थानों पर जहां "some_API_callback_func" के लिए रूपरेखा अच्छी तरह से प्रलेखित में नहीं इस्तेमाल किया जाता है यह ठीक काम करता है।

+0

धन्यवाद, लेकिन यह वही है जो मैंने लिनक्स कर्नेल में कंटेनर_ओफ़ मैक्रो के संबंध में पहले ही वर्णित किया है। –

2

असल में, कुछ भी आप सी ++ में सदस्य (T::*) के सूचक के साथ क्या होता ++ सी में offsetof के उपयोग के कारण है कि लिए एक अच्छे उम्मीदवार, offsetof सी में बहुत दुर्लभ है।

अब इस पाठ्यक्रम का एक सा परिपत्र है, इसलिए यहाँ कुछ उदाहरण हैं:

structs के लिए
  • अर्द्ध सामान्य छंटाई कार्य करता है। qsort कॉलबैक का उपयोग करता है, जो आदर्श नहीं है। अक्सर आपको केवल एक सदस्य के प्राकृतिक क्रम से क्रमबद्ध करने की आवश्यकता होती है, उदा। एक संरचना में तीसरा int। इस उद्देश्य के लिए एक काल्पनिक qsort_intoffsetof तर्क स्वीकार कर सकता है।
  • इसी तरह, यह है कि आप कह सकते हैं int out[10]; extract(int, &MyFoo[0], &MyFoo[10], out, offsetof(struct Foo, Bar));
5

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

'बुराई' के संबंध में, आपको याद रखना होगा कि परंपरागत रूप से 'सी' प्रोग्रामिंग में बहुत सी चीजें जो विशेष रूप से संसाधन-सीमित प्लेटफार्मों पर की जाती हैं, अब आधुनिक कंप्यूटिंग के शानदार आसपास से देखे जाने पर बुराई हैकरी की तरह दिखती है ।

5

offsetof() में से एक वैध का उपयोग एक प्रकार के संरेखण निर्धारित करने के लिए है:

#define ALIGNMENT_OF(t) offsetof(struct { char x; t test; }, test) 

यह थोड़ा कम स्तर एक वस्तु के संरेखण की जरूरत करने के लिए हो सकता है लेकिन किसी भी मामले में मैं इस पर विचार कर रहे एक वैध उपयोग।

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