2015-08-11 8 views
7

मैं उद्देश्य को पोर्ट करने के लिए लाइब्रेरी लपेटने की कोशिश कर रहा हूं। पुस्तकालय में एक समारोह का कहना है कि उजागर -रैपिंग फ़ंक्शन पॉइंटर

fooLib(int , char , function pointer A); 

समारोह सूचक एक के हस्ताक्षर

void handler(DataFormat); 

जहां DataFormat एक struct

मैं अपने आवरण इस लाइब्रेरी की कॉलबैक फ़ंक्शन को बेनकाब नहीं करना चाहती है । मैं एक अलग समारोह है कि मेरे आवरण के उपभोक्ताओं द्वारा इस्तेमाल किया जाना चाहिए बनाना चाहते हैं, कहते हैं कि

int handlerNew(NewDataFormat); 

जहां NewDataFormat मेरी struct

सवाल अब है कि मैं इन दोनों कार्यों लिंक कर सकते हैं? जब भी लाइब्रेरी handler कॉल करती है, तो मैं DataFormat से NewDataFormat संरचना को भरने के बाद इसे अपने कॉलबैक handlerNew पर कॉल करना चाहता हूं।

+1

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

+0

यह सच है, लेकिन यह पुस्तकालय कोई शून्य * सूचक नहीं लेता है। – Saaras

+0

यह थोड़ा अस्पष्ट है कि सभी बिट्स एक साथ कैसे फिट होते हैं। 'FooLib' का उपयोग कैसे किया जाता है? पुस्तकालय कैसे '/ हैंडलर' का आह्वान करता है? क्लाइंट कोड आपके रैपर का उपयोग कैसे करता है - आपने केवल इतना कहा है कि रैपर में 'हैंडलर नया' फ़ंक्शन है लेकिन इसका अर्थ यह है कि इसे लाइब्रेरी द्वारा कॉल किया जाता है, न कि क्लाइंट कोड। तो क्लाइंट कोड क्या करता है - मूल पुस्तकालय या आपका रैपर? – kaylum

उत्तर

5

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

// wrapped_foo_lib.h 
typedef struct { ... } NewDataFormat; 
typedef void (*WRAPPED_CALLBACK)(NewDataFormat); 
void wrappedFooLibCall(int x, char c, WRAPPED_CALLBACK cb); 

आपका कार्यान्वयन, जो ग्राहक को देखने के लिए हो जाता है कभी नहीं है:

// wrapped_foo_lib.c 
// This static var makes this module _not_ thread safe. 
static WRAPPED_CALLBACK wrapped_callback; 

static void private_handler(DataFormat data) { 
    NewDataFormat new_data = ...; // extract new_data from data 
    wrapped_callback(new_data); 
} 

void wrappedFooLibCall(int x, char c, WRAPPED_CALLBACK cb) { 
    wrapped_callback = cb;  
    foo_lib(x, c, private_handler); 
} 

गैर धागा सुरक्षा कारण है कि हर API कॉलबैक एक void * कि आप शामिल होना चाहिए परिभाषित करने के लिए, जो कॉलबैक पर भेजा जाता है। अर्थात। अपने तरीके से सुसज्जित पुस्तकालय अब जब आप fooLib कहते हैं, आप बिल्कुल env रूप में किसी भी struct प्रस्तुत के रूप में

fooLib(int, char, void (*)(DataFormat, void *env)); 
void handler(DataFormat, void *env); 

परिभाषित किया जाना चाहिए, और इसे वापस आप के लिए पारित किया है। इस तरह से आप आवरण में स्थिर चर के साथ बांटना कर सकते हैं:

// wrapped_foo_lib.c 
typedef struct { WRAPPED_CALLBACK wrapped_callback; } ENV; 

static void private_handler(DataFormat data, void *void_env) { 
    ENV *env = (ENV*)void_env; 
    NewDataFormat new_data = ...; // extract new_data from data 
    env->wrapped_callback(new_data); 
} 

void wrappedFooLibCall(int x, char c, WRAPPED_CALLBACK cb) { 
    ENV env[1] = {{ cb }};  
    foo_lib(x, c, env); 
} 

यह धागा सुरक्षित क्योंकि ENV आवंटित ढेर कर रहा है। इस अच्छा प्रदर्शन का एक अच्छा उदाहरण libpng है।

सी 9 0 को अधिक आधुनिक वाक्यविन्यास में अपडेट करने के लिए स्वतंत्र महसूस करें।

+1

में उपयोग करने जा रहा हूं जीसीसी में कम से कम आप 'स्थिर WRAPPED_CALLBACK wrapped_callback' को बदलकर थ्रेड सुरक्षा समस्या को पार कर सकते हैं; '__thread WRAPPED_CALLBACK wrapped_callback;'। Wrapped_callback चर तब एक थ्रेड-ग्लोबल वैरिएबल है, इसलिए प्रति थ्रेड सुरक्षित रूप से सेट किया जा सकता है। – bazza

+0

यह काम करेगा, केवल चिंता यह है कि यदि मेरे ग्राहक एकाधिक कॉलबैक पंजीकृत करना चाहते हैं, तो केवल अंतिम पंजीकृत कॉलबैक को स्थैतिक चर द्वारा याद किया जाएगा। क्या इसके आसपास कोई है। – Saaras

+0

@ सारास, लपेटा FooLibCall एक सूचक के बजाय कॉल बैक फ़ंक्शन पॉइंटर्स की एक सूची या सरणी ले सकता है। स्थिर चर उस सूची की एक प्रति हो सकती है, और निजी हैंडलर प्रत्येक हैंडलर को बदले में सूची में बस फिर से चालू करेगा। – bazza

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