2009-12-03 22 views
32

के रूप में फ़ंक्शन पास करने के लिए मैं एक सी ++ ऐप में सी लाइब्रेरी का उपयोग करने की कोशिश कर रहा हूं और मुझे अपनी स्थिति निम्न स्थिति में मिली है (मुझे पता है कि मेरा सी है, लेकिन मैं सी ++ के लिए बिल्कुल नया हूं)। सी पक्ष में मेरे पास फ़ंक्शंस का संग्रह है जो फ़ंक्शन पॉइंटर को उनके तर्क के रूप में लेता है। सी ++ तरफ मेरे पास एक मज़ेदार के साथ ऑब्जेक्ट्स हैं जिनके पास सी फ़ंक्शन द्वारा आवश्यक फ़ंक्शन पॉइंटर के समान हस्ताक्षर है। क्या C++ फ़ंक्शन को सी फ़ंक्शन को पास करने के लिए फ़ंक्शन पॉइंटर के रूप में उपयोग करने का कोई तरीका है?फ़ंक्शन पॉइंटर

उत्तर

46

आप सी कोड (या यहां तक ​​कि सी ++ कोड) के फ़ंक्शन पॉइंटर के रूप में सी ++ फ़ैक्टर ऑब्जेक्ट पर सीधे पॉइंटर पास नहीं कर सकते हैं।

साथ ही, portably सी कोड के लिए एक कॉलबैक यह कम से कम एक extern "C" गैर सदस्य समारोह के रूप में घोषित किए जाने की आवश्यकता पारित करने के लिए। कम से कम, क्योंकि कुछ एपीआई को विशिष्ट फ़ंक्शन कॉल सम्मेलनों की आवश्यकता होती है और इस प्रकार अतिरिक्त घोषणा संशोधक की आवश्यकता होती है।

कई वातावरण में सी और सी ++ में समान कॉलिंग सम्मेलन होते हैं और नाम मैंगलिंग में केवल भिन्न होते हैं, इसलिए कोई भी वैश्विक फ़ंक्शन या स्थैतिक सदस्य काम करेगा। लेकिन आपको अभी भी सामान्य फ़ंक्शन में कॉल को operator() पर लपेटने की आवश्यकता है।

  • अपने functor कोई राज्य नहीं हैं (यह एक वस्तु बस कुछ औपचारिक आवश्यकताओं आदि को पूरा करने के लिए है):

    class MyFunctor { 
        // no state 
    public: 
        MyFunctor(); 
        int operator()(SomeType &param) const; 
    } 
    

    आप एक सामान्य extern "सी" समारोह जो functor बनाता लिख ​​सकते हैं और अपने ऑपरेटर() को निष्पादित करता है।

    extern "C" int MyFunctorInC(SomeType *param) 
    { 
        static MyFunctor my_functor; 
        return my_functor(*param); 
    } 
    
  • यदि आपका functor राज्य, जैसे हैं:

    void MyAlgorithmInC(SomeType *arr, 
            int (*fun)(SomeType *, void *), 
            void *user_state); 
    

    :

    class MyFunctor { 
        // Some fields here; 
    public: 
        MyFunctor(/* some parameters to set state */); 
        int operator()(SomeType &param) const; 
        // + some methods to retrieve result. 
    } 
    

    और सी कॉलबैक फ़ंक्शन कुछ (* आमतौर पर शून्य) उपयोगकर्ता राज्य पैरामीटर के प्रकार लेता है आप एक सामान्य बाहरी "सी" फ़ंक्शन लिख सकते हैं जो पर आपके राज्य पैरामीटर को आपके मज़ेदार ऑब्जेक्ट पर रखता है:

    extern "C" int MyFunctorInC(SomeType *param, void *user_state) 
    { 
        MyFunctor *my_functor = (MyFunctor *)user_state; 
        return (*my_functor)(*param); 
    } 
    

    और इस तरह इसका इस्तेमाल:

    MyFunctor my_functor(/* setup parameters */); 
    MyAlgorithmInC(input_data, MyFunctorInC, &my_functor); 
    
  • अन्यथा केवल सामान्य तरीके से (आदि "रनटाइम पर मशीन कोड उत्पन्न किए बिना" के रूप में सामान्य) यह करने के लिए कुछ का उपयोग करने के लिए है स्थिर (वैश्विक) या धागा स्थानीय भंडारण फ्लाटर को बाहरी "सी" फ़ंक्शन में पास करने के लिए। यह सीमा है कि आप अपने कोड के साथ क्या कर सकते हैं और बदसूरत है लेकिन काम करेगा।

+0

+1 पर रनटाइम त्रुटि, संभावित मामलों का विस्तृत लेखन। –

+0

+1, हालांकि कॉलबैक हस्ताक्षर निश्चित रूप से सी नहीं है :) – quinmars

+0

ओह, एनवीएम, किसी भी तरह से मैंने घोषणाओं को मिश्रित किया और सोचा कि आप यहां सी में संदर्भों का उपयोग कर रहे हैं। – quinmars

2

मुझे नहीं लगता कि आप कर सकते हैं: operator() फ़ंक्शन ऑब्जेक्ट में वास्तव में एक सदस्य फ़ंक्शन है, और सी उन लोगों के बारे में कुछ नहीं जानता है।

आपको क्या उपयोग करने में सक्षम होना चाहिए मुफ्त सी ++ फ़ंक्शंस, या कक्षाओं के स्थिर कार्य हैं।

0

यह निर्भर करता है अगर यह एक स्थिर या उदाहरण विधि है, अगर यह तो स्थिर आप, के रूप में className :: functionName समारोह के माध्यम से पारित कर सकते हैं अगर यह एक उदाहरण विधि यह उचित अधिक जटिल है है, क्योंकि आप स्पष्ट रूप से टाई करने की जरूरत है एक निश्चित उदाहरण के लिए, लेकिन के रूप में आप सी # में प्रतिनिधियों के साथ होता है उसी तरह से यह नहीं कर सकते आदि

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

3

नहीं, ज़ाहिर है। आपके सी फ़ंक्शन का हस्ताक्षर फ़ंक्शन के रूप में तर्क लेता है।

void f(void (*func)()) 
{ 
    func(); // Only void f1(), void F2(), .... 
} 

functors के साथ सभी चालें टेम्पलेट कार्यों द्वारा किया जाता है:

template<class Func> 
void f (Func func) 
{ 
    func(); // Any functor 
} 
0

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

0

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

template<class T> 
int function_wrapper(int a, int b) { 
    T function_object_instance; 

    return funcion_object_instance(a, b); 
} 

यह दो चींटियों को लेने और एक int वापस करने वाले सभी कार्यों के लिए करेगा।

7

मुझे Google का उपयोग करके यह "gem" मिला। जाहिर है, लेकिन मुझे यकीन है कि यह सिफारिश नहीं करेगा। उदाहरण स्रोत कोड के लिए डायरेक्ट link

+0

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

+3

यक, यह वास्तव में "काला जादू" श्रेणी के नाम के रूप में दर्ज किया गया है, जिसके तहत यह दर्ज किया गया है – 0xC0000022L

+0

शुद्ध मणि मुझे लगता है कि यह एकमात्र तरीका है, क्योंकि सी कॉलर को अतिरिक्त पैरामीटर को कैसे धक्का देना नहीं है। फ़्रेम में फ़ंक्शन बनाया गया है जिसमें यह "कॉन्स्ट" कॉलर है। –

3

सी ++ में लिखे गए एक सी कॉलबैक फ़ंक्शन को extern "C" फ़ंक्शन के रूप में घोषित किया जाना चाहिए - इसलिए एक मज़ेदार का उपयोग सीधे बाहर हो जाता है। आपको उस कॉलबैक के रूप में उपयोग करने के लिए कुछ प्रकार के रैपर फ़ंक्शन लिखने की आवश्यकता होगी और उस रैपर को मज़ेदार को कॉल करें। बेशक, कॉलबैक प्रोटोकॉल को फ़ंक्शन में संदर्भ पारित करने का कोई तरीका होना चाहिए ताकि यह मजेदार हो सके, या कार्य काफी मुश्किल हो जाता है। अधिकांश कॉलबैक योजनाओं में संदर्भ पारित करने का एक तरीका होता है, लेकिन मैंने कुछ मस्तिष्क-मृत लोगों के साथ काम किया है जो नहीं करते हैं।

कुछ और जानकारी के लिए इस उत्तर देखें (और वास्तविक सबूत के लिए टिप्पणी में लग रही है कि कॉलबैक extern "C" और न सिर्फ एक स्थिर सदस्य समारोह होना चाहिए):

0

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

अन्यथा, नहीं।

1

जीसीसी आप सादे समारोह संकेत करने के लिए सदस्य समारोह संकेत कन्वर्ट करने के लिए अनुमति देता है (समारोह सादे समारोह सूचक द्वारा कहा जाता है की पहला तर्क तो this है)।

respective link in the manual देखें।

यह निश्चित रूप से गैर-मानक सुविधा के लिए संबंधित चेतावनी को चुप करने के लिए -Wno-pmf-conversions ध्वज की आवश्यकता है। सी ++ शैली प्रोग्रामिंग के साथ सी शैली पुस्तकालयों interfacing के लिए बहुत सुविधाजनक है। जब सदस्य फ़ंक्शन पॉइंटर स्थिर होता है, तो उसे किसी भी कोड को भी उत्पन्न करने की आवश्यकता नहीं होती है: एपीआई वैसे भी उस तर्क आदेश का उपयोग करेगा।

यदि आपके पास पहले से ही एक मज़ेदार है, तो इस तरह से मज़ेदार को फटकारने का मतलब यह होगा कि operator() को फ़्लैटन करने का मतलब होगा, जिससे आपको एक ऐसा फ़ंक्शन दिया जा सके जिसे फेंक्टर क्लास पॉइंटर के साथ अपने पहले तर्क के रूप में बुलाया जाए। जो जरूरी नहीं कि वह सब कुछ मदद करता है लेकिन कम से कम सी लिंकेज है।

लेकिन कम से कम जब आप फ़ैक्टर के माध्यम से नहीं जा रहे हैं तो यह उपयोगी है और <functional> से std::mem_fn के लिए नो-बकवास सी लिंकेज प्रतिस्थापन प्रदान करता है।

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