C में फंक्शन पॉइंटर्स के लिए टाईपडेफ्स को समझना


237

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


1
क्या आप कुछ उदाहरण प्रदान कर सकते हैं?
आर्टिलियस

2
क्या आप फ़ंक्शन पॉइंटर्स के लिए मैक्रोज़ के बजाय फंक्शन पॉइंटर्स के लिए टाइपराइफ़्स का मतलब नहीं रखते हैं? मैंने पूर्व को देखा है, लेकिन बाद को नहीं।
dave4420

जवाबों:


297

signal()सी मानक से कार्य पर विचार करें :

extern void (*signal(int, void(*)(int)))(int);

पूरी तरह से अस्पष्ट रूप से स्पष्ट है - यह एक ऐसा फ़ंक्शन है जो दो तर्कों को लेता है, एक पूर्णांक और एक फ़ंक्शन के लिए एक सूचक जो एक तर्क के रूप में एक पूर्णांक लेता है और कुछ भी नहीं देता है, और यह ( signal()) एक फ़ंक्शन को एक सूचक देता है जो पूर्णांक को एक तर्क के रूप में लेता है और वापस लौटता है कुछ भी तो नहीं।

यदि आप लिखते हैं:

typedef void (*SignalHandler)(int signum);

तो आप इसके signal()रूप में घोषित कर सकते हैं :

extern  SignalHandler signal(int signum, SignalHandler handler);

इसका मतलब वही है, लेकिन आमतौर पर इसे पढ़ने में कुछ आसान माना जाता है। यह स्पष्ट है कि फ़ंक्शन intSignalHandlerऔर ए लेता है SignalHandler

हालाँकि, इसका उपयोग करने में थोड़ा समय लगता है। एक चीज़ जो आप नहीं कर सकते हैं, हालांकि SignalHandler typedefफ़ंक्शन परिभाषा में एक सिग्नल हैंडलर फ़ंक्शन का उपयोग करके लिखा गया है।

मैं अभी भी पुराने स्कूल का हूँ जो एक फंक्शन पॉइंटर को इनवाइट करना पसंद करता है:

(*functionpointer)(arg1, arg2, ...);

आधुनिक वाक्यविन्यास बस का उपयोग करता है:

functionpointer(arg1, arg2, ...);

मैं यह देख सकता हूं कि वह काम क्यों करता है - मैं सिर्फ यह जानना पसंद करता हूं कि मुझे यह देखने की जरूरत है कि किसी फ़ंक्शन के लिए वेरिएबल को इनिशियलाइज़ करने की बजाय कहा जाता है functionpointer


सैम ने टिप्पणी की:

इसका स्पष्टीकरण मैंने पहले भी देखा है। और फिर, जैसा कि अभी मामला है, मुझे लगता है कि मुझे जो नहीं मिला वह दो बयानों के बीच का संबंध था:

    extern void (*signal(int, void()(int)))(int);  /*and*/

    typedef void (*SignalHandler)(int signum);
    extern SignalHandler signal(int signum, SignalHandler handler);

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

चलो फिर से कोशिश करें। इनमें से पहला सी मानक से सीधे उठा हुआ है - मैंने इसे हटा दिया, और जांच की कि मेरे पास कोष्ठक सही थे (जब तक मैंने इसे सही नहीं किया - यह याद रखने के लिए एक कठिन कुकी है)।

सबसे पहले, याद रखें कि typedefएक प्रकार के लिए एक उपनाम का परिचय देता है। तो, उपनाम है SignalHandlerऔर इसका प्रकार है:

किसी फ़ंक्शन के लिए एक संकेतक जो एक तर्क के रूप में पूर्णांक लेता है और कुछ भी नहीं देता है।

'रिटर्न नथिंग' भाग वर्तनी है void; एक पूर्णांक है कि तर्क (मुझे विश्वास है) आत्म व्याख्यात्मक है। निम्नलिखित संकेतन बस (या नहीं) है कि कैसे सी सूचक इंगित करने के लिए तर्क देने के लिए कार्य करता है और दिए गए प्रकार को वापस करता है:

type (*function)(argtypes);

सिग्नल हैंडलर प्रकार बनाने के बाद, मैं इसका उपयोग चर और अन्य को घोषित करने के लिए कर सकता हूं। उदाहरण के लिए:

static void alarm_catcher(int signum)
{
    fprintf(stderr, "%s() called (%d)\n", __func__, signum);
}

static void signal_catcher(int signum)
{
    fprintf(stderr, "%s() called (%d) - exiting\n", __func__, signum);
    exit(1);
}

static struct Handlers
{
    int              signum;
    SignalHandler    handler;
} handler[] =
{
    { SIGALRM,   alarm_catcher  },
    { SIGINT,    signal_catcher },
    { SIGQUIT,   signal_catcher },
};

int main(void)
{
    size_t num_handlers = sizeof(handler) / sizeof(handler[0]);
    size_t i;

    for (i = 0; i < num_handlers; i++)
    {
        SignalHandler old_handler = signal(handler[i].signum, SIG_IGN);
        if (old_handler != SIG_IGN)
            old_handler = signal(handler[i].signum, handler[i].handler);
        assert(old_handler == SIG_IGN);
    }

    ...continue with ordinary processing...

    return(EXIT_SUCCESS);
}

कृपया ध्यान दें कि सिग्नल हैंडलर में उपयोग करने से कैसे बचें printf()?

तो, हमने यहाँ क्या किया है - 4 मानक हेडर के अलावा जो कोड को साफ-सुथरा बनाने के लिए आवश्यक होगा?

पहले दो कार्य ऐसे कार्य हैं जो एक पूर्णांक लेते हैं और कुछ भी नहीं लौटाते हैं। उनमें से एक वास्तव में सभी धन्यवाद पर वापस नहीं आता है, exit(1);लेकिन दूसरा एक संदेश को प्रिंट करने के बाद वापस करता है। ध्यान रखें कि सी मानक आपको सिग्नल हैंडलर के अंदर बहुत कुछ करने की अनुमति नहीं देता है; POSIX इजाज़त में थोड़ा और उदार है, लेकिन आधिकारिक तौर पर कॉलिंग को मंजूरी नहीं देता है fprintf()। मुझे जो सिग्नल नंबर मिला था, उसका प्रिंट आउट भी ले लेता हूं। में alarm_handler()समारोह, मूल्य हमेशा रहेंगे SIGALRMरूप में है कि केवल संकेत है कि इसके लिए एक हैंडलर है, लेकिन signal_handler()मिल सकता है SIGINTया SIGQUITसंकेत संख्या के रूप में, क्योंकि एक ही समारोह दोनों के लिए प्रयोग किया जाता है।

फिर मैं संरचनाओं की एक सरणी बनाता हूं, जहां प्रत्येक तत्व एक सिग्नल संख्या की पहचान करता है और उस सिग्नल के लिए हैंडलर स्थापित किया जाता है। मैंने 3 संकेतों के बारे में चिंता करने के लिए चुना है; मैं अक्सर के बारे में चिंता है SIGHUP, SIGPIPEऔर SIGTERMभी और के बारे में कि क्या वे ( #ifdefसशर्त संकलन) परिभाषित कर रहे हैं , लेकिन यह सिर्फ चीजों को जटिल करता है। मैं शायद sigaction()इसके बजाय POSIX का उपयोग करूँगा signal(), लेकिन यह एक और मुद्दा है; चलो जो हमने शुरू किया था, उसके साथ चलो।

main()संचालकों की सूची पर समारोह दोहराता स्थापित होने के लिए। प्रत्येक हैंडलर के लिए, यह पहले यह signal()पता लगाने के लिए कॉल करता है कि क्या प्रक्रिया वर्तमान में सिग्नल की अनदेखी कर रही है, और ऐसा करते समय, SIG_IGNहैंडलर के रूप में स्थापित होता है , जो यह सुनिश्चित करता है कि सिग्नल को नजरअंदाज किया जाता है। यदि सिग्नल को पहले नजरअंदाज नहीं किया गया था, तो यह फिर से कॉल करता है signal(), इस बार पसंदीदा सिग्नल हैंडलर को स्थापित करने के लिए। (दूसरा मान निश्चित SIG_DFLरूप से, सिग्नल के लिए डिफ़ॉल्ट सिग्नल हैंडलर है।) क्योंकि 'सिग्नल' () के लिए पहला कॉल हैंडलर को सेट करता है SIG_IGNऔर signal()पिछले त्रुटि हैंडलर को लौटाता है, बयान के oldबाद का मान ifहोना चाहिए SIG_IGN- इसलिए जोर। (खैर, यह हो सकता हैSIG_ERR अगर कुछ नाटकीय रूप से गलत हो गया - लेकिन तब मैं उस बारे में जानूंगा जो मुखर गोलीबारी से हुई है।]

कार्यक्रम फिर अपना सामान करता है और सामान्य रूप से बाहर निकलता है।

ध्यान दें कि किसी फ़ंक्शन का नाम उपयुक्त प्रकार के फ़ंक्शन के लिए एक संकेतक के रूप में माना जा सकता है। जब आप फ़ंक्शन-कॉल कोष्ठकों को लागू नहीं करते हैं - जैसे कि शुरुआती में, उदाहरण के लिए - फ़ंक्शन का नाम फ़ंक्शन पॉइंटर बन जाता है। यह भी है कि pointertofunction(arg1, arg2)संकेतन के माध्यम से कार्यों को लागू करना उचित है; जब आप देखते हैं alarm_handler(1), तो आप विचार कर सकते हैं कि alarm_handlerफ़ंक्शन के लिए एक पॉइंटर है और इसलिए alarm_handler(1)फ़ंक्शन पॉइंटर के माध्यम से फ़ंक्शन का एक आह्वान है।

इसलिए, इस प्रकार, मैंने दिखाया है कि एक SignalHandlerचर का उपयोग करने के लिए अपेक्षाकृत सीधा-आगे है, जब तक कि आपके पास इसे असाइन करने के लिए कुछ सही प्रकार का मूल्य है - जो कि दो सिग्नल हैंडलर फ़ंक्शन प्रदान करता है।

अब हम इस प्रश्न पर वापस आते हैं - signal()एक दूसरे से संबंधित दो घोषणाएँ कैसे होती हैं ।

आइए दूसरी घोषणा की समीक्षा करें:

 extern SignalHandler signal(int signum, SignalHandler handler);

यदि हमने फ़ंक्शन का नाम और प्रकार इस प्रकार बदला है:

 extern double function(int num1, double num2);

आपको किसी ऐसे फ़ंक्शन के रूप में व्याख्या करने में कोई समस्या नहीं होगी जो intएक doubleतर्क और एक तर्क के रूप में लेता है और एक doubleमान लौटाता है (हो सकता है); यदि आप समस्याग्रस्त हैं तो बेहतर नहीं होगा '- लेकिन शायद आपको कठिन सवाल पूछने के बारे में सतर्क रहना चाहिए यह एक के रूप में अगर यह एक समस्या है)।

अब, एक होने के बजाय double, signal()फ़ंक्शन SignalHandlerअपने दूसरे तर्क के रूप में लेता है , और यह एक परिणाम के रूप में वापस आता है।

यांत्रिकी जिसके द्वारा भी इलाज किया जा सकता है:

extern void (*signal(int signum, void(*handler)(int signum)))(int signum);

समझाने के लिए मुश्किल कर रहे हैं - तो मैं शायद इसे खराब कर दूँगा। इस बार मैंने पैरामीटर नाम दिए हैं - हालांकि नाम महत्वपूर्ण नहीं हैं।

सामान्य तौर पर, C में, घोषणा तंत्र ऐसा होता है कि यदि आप लिखते हैं:

type var;

तब जब आप लिखते हैं तो varयह दिए गए मान का प्रतिनिधित्व करता है type। उदाहरण के लिए:

int     i;            // i is an int
int    *ip;           // *ip is an int, so ip is a pointer to an integer
int     abs(int val); // abs(-1) is an int, so abs is a (pointer to a)
                      // function returning an int and taking an int argument

मानक में, typedefव्याकरण में एक भंडारण वर्ग के रूप में व्यवहार किया जाता है, न कि तरह staticऔर externभंडारण वर्ग हैं।

typedef void (*SignalHandler)(int signum);

इसका मतलब यह है कि जब आप एक प्रकार का चर देखते हैं SignalHandler(अलार्म_हैंडलर कहते हैं):

(*alarm_handler)(-1);

परिणाम type voidका कोई परिणाम नहीं है। और तर्क (*alarm_handler)(-1);के alarm_handler()साथ एक आह्वान है -1

इसलिए, अगर हमने घोषित किया:

extern SignalHandler alt_signal(void);

इसका मतलब है कि:

(*alt_signal)();

एक शून्य मान का प्रतिनिधित्व करता है। और इसीलिए:

extern void (*alt_signal(void))(int signum);

समतुल्य है। अब, signal()अधिक जटिल है क्योंकि यह न केवल एक रिटर्न देता है SignalHandler, यह एक अंतर और SignalHandlerतर्क के रूप में भी स्वीकार करता है:

extern void (*signal(int signum, SignalHandler handler))(int signum);

extern void (*signal(int signum, void (*handler)(int signum)))(int signum);

यदि वह अभी भी आपको भ्रमित करता है, तो मुझे यकीन नहीं है कि मैं कैसे मदद कर सकता हूं - यह अभी भी मेरे लिए कुछ स्तरों पर रहस्यमय है, लेकिन मैं इसे कैसे काम करता है, इसके लिए उपयोग किया गया है और इसलिए आपको बता सकता है कि यदि आप इसके साथ एक और 25 साल तक चिपके रहते हैं या तो, यह आपके लिए दूसरा स्वभाव बन जाएगा (और शायद थोड़ा तेज भी अगर आप चतुर हैं)।


3
इसका स्पष्टीकरण मैंने पहले भी देखा है। और फिर, जैसा कि अभी मामला है, मुझे लगता है कि मुझे जो नहीं मिला वह दो बयानों के बीच संबंध था: बाहरी शून्य ( संकेत (int, void ( ) (int))) (int); / * और * / typedef। शून्य (* सिग्नलहैंडलर) (इंट साइनम); बाहरी सिग्नलहैंडलर सिग्नल (इंट साइनम, सिग्नलहैंडलर हैंडलर); या, मैं जो पूछना चाहता हूं, वह अंतर्निहित अवधारणा क्या है जिसका उपयोग आप दूसरे संस्करण के साथ आने के लिए कर सकते हैं? मूलभूत क्या है जो "सिग्नलहैंडलर" और पहला टाइपडेफ़ को जोड़ता है? मुझे लगता है कि यहां जो बताया जाना चाहिए, वह वही है जो वास्तव में टाइप्डिफ है। Thx

6
शानदार जवाब, मुझे खुशी है कि मैं इस धागे पर वापस आया। मुझे नहीं लगता कि मैं सब कुछ समझता हूं, लेकिन एक दिन मैं करूंगा। यही कारण है कि मुझे एसओ पसंद है। धन्यवाद।
टोटो

2
बस एक नाइट लेने के लिए: यह एक सिग्नल हैंडलर के अंदर प्रिंटफ () और दोस्तों को कॉल करने के लिए सुरक्षित नहीं है; प्रिंटफ () फिर से प्रवेश नहीं है (मूल रूप से क्योंकि इसे
मॉलोक

4
इसका extern void (*signal(int, void(*)(int)))(int);मतलब है कि signal(int, void(*)(int))फ़ंक्शन एक फ़ंक्शन पॉइंटर को लौटा देगा void f(int)। जब आप फ़ंक्शन पॉइंटर को रिटर्न वैल्यू के रूप में निर्दिष्ट करना चाहते हैं , तो सिंटैक्स जटिल हो जाता है। आपको वापसी मान प्रकार को बाईं ओर और तर्क सूची को दाईं ओर रखना होगा , जबकि यह मध्य है जिसे आप परिभाषित कर रहे हैं। और इस मामले में, signal()फ़ंक्शन अपने पैरामीटर के रूप में फ़ंक्शन पॉइंटर लेता है, जो चीजों को और भी अधिक जटिल करता है। अच्छी खबर है, अगर आप इसे पढ़ सकते हैं, तो फोर्स पहले से ही आपके साथ है। :)।
smwikipedia

1
&फ़ंक्शन नाम के सामने उपयोग करने के बारे में पुराना स्कूल क्या है ? यह पूरी तरह से अनावश्यक है; व्यर्थ, यहां तक ​​कि। और निश्चित रूप से "पुराने स्कूल" नहीं। पुराने स्कूल सादे और सरल फंक्शन नाम का उपयोग करते हैं।
जोनाथन लेफ़लर

80

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

इसलिए उदाहरण के लिए मान लें कि आपका कोई कार्य है:

float doMultiplication (float num1, float num2 ) {
    return num1 * num2; }

इसके बाद निम्न टाइप करें:

typedef float(*pt2Func)(float, float);

इस doMulitplicationफ़ंक्शन को इंगित करने के लिए उपयोग किया जा सकता है । यह केवल एक फ़ंक्शन को एक पॉइंटर को परिभाषित करता है जो एक फ्लोट देता है और दो पैरामीटर लेता है, प्रत्येक प्रकार का फ्लोट। इस परिभाषा का अनुकूल नाम है pt2Func। ध्यान दें कि pt2Funcकिसी भी फ़ंक्शन को इंगित किया जा सकता है जो एक फ्लोट लौटाता है और 2 फ़्लोट्स में लेता है।

तो आप एक पॉइंटर बना सकते हैं जो ड्यूल्टिप्लीकेशन फंक्शन की ओर इशारा करता है:

pt2Func *myFnPtr = &doMultiplication;

और आप इस पॉइंटर का उपयोग करके फ़ंक्शन को निम्नानुसार लागू कर सकते हैं:

float result = (*myFnPtr)(2.0, 5.1);

यह पढ़ने में अच्छा बनाता है: http://www.newty.de/fpt/index.html


psychotik, धन्यवाद! यह मददगार था। फंक्शन पॉइंटर्स वेब पेज का लिंक वास्तव में मददगार है। इसे अभी पढ़ रहे हैं।

... हालाँकि, वह newty.de लिंक टाइप किए गए सभी के बारे में बात करने के लिए प्रकट नहीं होता है :( इसलिए भले ही वह लिंक बहुत अच्छा है, लेकिन टाइप किए गए के बारे में इस थ्रेड में प्रतिक्रियाएं अमूल्य हैं!

11
आप pt2Func myFnPtr = &doMultiplication;इसके बजाय करना चाहते थे pt2Func *myFnPtr = &doMultiplication;क्योंकि myFnPtrपहले से ही एक सूचक है।
तमिलसेल्वन

1
pt2Func * myFnPtr = & doMultiplication घोषित करना; बजाय pt2Func myFnPtr = & doMultiplication के बजाय; एक चेतावनी फेंकता है।
अल्फगोकू

2
@ तमीलसेल्वन सही है। myFunPtrपहले से ही एक फ़ंक्शन पॉइंटर है, इसलिए उपयोग करेंpt2Func myFnPtr = &doMultiplication;
Dustin Biser

35

फ़ंक्शन पॉइंटर के टाइपफेड को समझने का एक बहुत आसान तरीका:

int add(int a, int b)
{
    return (a+b);
}

typedef int (*add_integer)(int, int); //declaration of function pointer

int main()
{
    add_integer addition = add; //typedef assigns a new variable i.e. "addition" to original function "add"
    int c = addition(11, 11);   //calling function via new variable
    printf("%d",c);
    return 0;
}

32

cdeclफ़ंक्शन पॉइंटर घोषणाओं जैसे अजीब सिंटैक्स को डिक्रिप करने के लिए एक महान उपकरण है। आप उन्हें उत्पन्न करने के लिए भी इसका उपयोग कर सकते हैं।

जहां तक ​​भविष्य के रखरखाव (अपने या अन्य लोगों के लिए) के लिए जटिल घोषणाओं को आसान बनाने की युक्तियों का सुझाव है, मैं typedefछोटे चंक्स बनाने की सलाह देता हूं और उन छोटे टुकड़ों का उपयोग बड़े और अधिक जटिल अभिव्यक्तियों के लिए निर्माण ब्लॉक के रूप में करता हूं । उदाहरण के लिए:

typedef int (*FUNC_TYPE_1)(void);
typedef double (*FUNC_TYPE_2)(void);
typedef FUNC_TYPE_1 (*FUNC_TYPE_3)(FUNC_TYPE_2);

बजाय:

typedef int (*(*FUNC_TYPE_3)(double (*)(void)))(void);

cdecl इस सामान के साथ आपकी मदद कर सकते हैं:

cdecl> explain int (*FUNC_TYPE_1)(void)
declare FUNC_TYPE_1 as pointer to function (void) returning int
cdecl> explain double (*FUNC_TYPE_2)(void)
declare FUNC_TYPE_2 as pointer to function (void) returning double
cdecl> declare FUNC_TYPE_3 as pointer to function (pointer to function (void) returning double) returning pointer to function (void) returning int
int (*(*FUNC_TYPE_3)(double (*)(void )))(void )

और (वास्तव में) वास्तव में मैंने कैसे उस पागल गंदगी को उत्पन्न किया।


2
हाय कार्ल, यह एक बहुत ही व्यावहारिक उदाहरण और स्पष्टीकरण था। इसके अलावा, cdecl के उपयोग को दिखाने के लिए धन्यवाद। बहुत सराहना की।

क्या खिड़कियों के लिए सीडीईसीएल है?
जैक

@ जेक, मुझे यकीन है कि आप इसका निर्माण कर सकते हैं, हाँ।
कार्ल नॉरम जूल

2
Cdecl.org भी है जो एक ही तरह की क्षमता प्रदान करता है लेकिन ऑनलाइन। हमारे लिए उपयोगी विंडोज डेवलपर्स।
zaknotzach

12
int add(int a, int b)
{
  return (a+b);
}
int minus(int a, int b)
{
  return (a-b);
}

typedef int (*math_func)(int, int); //declaration of function pointer

int main()
{
  math_func addition = add;  //typedef assigns a new variable i.e. "addition" to original function "add"
  math_func substract = minus; //typedef assigns a new variable i.e. "substract" to original function "minus"

  int c = addition(11, 11);   //calling function via new variable
  printf("%d\n",c);
  c = substract(11, 5);   //calling function via new variable
  printf("%d",c);
  return 0;
}

इसका आउटपुट है:

22

6

ध्यान दें, दोनों फ़ंक्शन को घोषित करने के लिए एक ही math_func निश्चित का उपयोग किया गया है।

टंकण के समान दृष्टिकोण का उपयोग बाहरी संरचना के लिए किया जा सकता है।


5

अधिक जटिल प्रकारों को परिभाषित करने के लिए टाइपडिफ्स का प्रयोग करें

मैं सी में एक राज्य-मशीन को परिभाषित करने का उदाहरण लूंगा

    typedef  int (*action_handler_t)(void *ctx, void *data);

अब हमने एक्शन_हैंडलर नामक एक प्रकार को परिभाषित किया है जो दो पॉइंटर्स लेता है और एक इंट देता है

अपनी राज्य-मशीन को परिभाषित करें

    typedef struct
    {
      state_t curr_state;   /* Enum for the Current state */
      event_t event;  /* Enum for the event */
      state_t next_state;   /* Enum for the next state */
      action_handler_t event_handler; /* Function-pointer to the action */

     }state_element;

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

मेरे सभी घटना संचालकों को अब एक्शन_हैंडलर द्वारा परिभाषित प्रकार का पालन करना चाहिए

    int handle_event_a(void *fsm_ctx, void *in_msg );

    int handle_event_b(void *fsm_ctx, void *in_msg );

संदर्भ:

लिंडेन द्वारा विशेषज्ञ सी प्रोग्रामिंग


4

यह फ़ंक्शन पॉइंटर्स और फ़ंक्शन पॉइंटर सरणियों का सबसे सरल उदाहरण है जिसे मैंने एक अभ्यास के रूप में लिखा था।

    typedef double (*pf)(double x);  /*this defines a type pf */

    double f1(double x) { return(x+x);}
    double f2(double x) { return(x*x);}

    pf pa[] = {f1, f2};


    main()
    {
        pf p;

        p = pa[0];
        printf("%f\n", p(3.0));
        p = pa[1];
        printf("%f\n", p(3.0));
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.