Typedef फ़ंक्शन पॉइंटर?


458

मैं सीख रहा हूँ कि कैसे DLL को गतिशील रूप से लोड करना है लेकिन जो मुझे समझ में नहीं आता है वह यह पंक्ति है

typedef void (*FunctionFunc)();

मेरे कुछ प्रश्न हैं। अगर कोई उन्हें जवाब देने में सक्षम है तो मैं आभारी रहूंगा।

  1. क्यों typedefइस्तेमाल किया जाता है?
  2. वाक्यविन्यास अजीब लगता है; उसके बाद voidएक फ़ंक्शन नाम या कुछ नहीं होना चाहिए? यह एक अनाम फ़ंक्शन की तरह दिखता है।
  3. क्या एक फ़ंक्शन पॉइंटर किसी फ़ंक्शन के मेमोरी एड्रेस को स्टोर करने के लिए बनाया गया है?

इसलिए मैं इस समय उलझन में हूं; क्या आप मेरे लिए चीजों को स्पष्ट कर सकते हैं?


5
लिंक पर एक नज़र डालें (अंतिम खंड) learncpp.com/cpp-tutorial/78-function-pointers
उत्साही

9
ध्यान दिया जाना चाहिए कि चूंकि सी ++ 11 using FunctionFunc = void (*)();का उपयोग इसके बजाय किया जा सकता है। यह थोड़ा और स्पष्ट है कि आप केवल एक प्रकार के लिए एक नाम घोषित कर रहे हैं (सूचक कार्य करने के लिए)
user362515

बस @ user362515 में जोड़ने के लिए, मेरे लिए थोड़ा स्पष्ट रूप है:using FunctionFunc = void(void);
टॉप्सपिन

@topspin IIRC ये दोनों समान नहीं हैं। एक एक फ़ंक्शन पॉइंटर प्रकार है, दूसरा फ़ंक्शन प्रकार है। इसमें निहित रूपांतरण है, इसीलिए यह काम करता है, IANA (C ++) L इसलिए, कोई भी इसमें कदम रख सकता है और मुझे सुधार सकता है। किसी भी मामले में, अगर इरादा एक पॉइंटर प्रकार को परिभाषित करना है, तो मुझे लगता है कि वाक्यविन्यास *थोड़ा अधिक स्पष्ट है।
user362515

जवाबों:


463

typedefएक भाषा निर्माण है जो एक नाम को एक प्रकार से जोड़ता है।
आप इसे उसी तरह उपयोग करते हैं जैसे आप मूल प्रकार का उपयोग करेंगे, उदाहरण के लिए

  typedef int myinteger;
  typedef char *mystring;
  typedef void (*myfunc)();

उनका उपयोग करना

  myinteger i;   // is equivalent to    int i;
  mystring s;    // is the same as      char *s;
  myfunc f;      // compile equally as  void (*f)();

जैसा कि आप देख सकते हैं, आप बस ऊपर दी गई परिभाषा के साथ टाइप किए गए नाम को बदल सकते हैं ।

सी और सी ++ में वाक्य रचना और पठनीयता के लिए सूचक में कठिनाई निहित है, और इस typedefतरह की घोषणाओं की पठनीयता में सुधार कर सकते हैं। हालाँकि, सिंटैक्स उपयुक्त है, क्योंकि फ़ंक्शंस - अन्य सरल प्रकारों के विपरीत - एक वापसी मूल्य और पैरामीटर हो सकते हैं, इस प्रकार कार्य करने के लिए एक पॉइंटर की कभी-कभी लंबी और जटिल घोषणा।

पठनीयता वास्तव में कार्य सारणी के संकेत के साथ मुश्किल हो सकती है, और कुछ अन्य भी अप्रत्यक्ष जायके।

अपने तीन सवालों के जवाब देने के लिए

  • टंकण का उपयोग क्यों किया जाता है? कोड की रीडिंग को आसान बनाने के लिए - विशेष रूप से कार्यों, या संरचना के नाम के संकेत के लिए।

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

  • क्या एक फ़ंक्शन पॉइंटर किसी फ़ंक्शन के मेमोरी एड्रेस को स्टोर करने के लिए बनाया गया है? हां, एक फ़ंक्शन पॉइंटर एक फ़ंक्शन का पता संग्रहीत करता है। इसका उस typedefनिर्माण से कोई लेना-देना नहीं है जो केवल एक कार्यक्रम के लिखने / पढ़ने में आसानी करता है; संकलक सिर्फ वास्तविक कोड को संकलित करने से पहले टाइपडीफ परिभाषा का विस्तार करता है।

उदाहरण:

typedef int (*t_somefunc)(int,int);

int product(int u, int v) {
  return u*v;
}

t_somefunc afunc = &product;
...
int x2 = (*afunc)(123, 456); // call product() to calculate 123*456

6
अंतिम उदाहरण में, 'स्क्वायर' केवल उसी चीज़ को इंगित नहीं करेगा जिसका उपयोग करने के बजाय फ़ंक्शन और पॉइंटर को इंगित करें।
प्रणव

2
प्रश्न, अपने पहले typedef उदाहरण में आप फार्म की है typedef type aliasलेकिन समारोह संकेत वहाँ के साथ ही, ऐसे 2 तर्कों प्रतीत हो रहा है typedef type। क्या उपनाम प्रकार तर्क में निर्दिष्ट नाम के लिए डिफ़ॉल्ट है?
dhethetri

2
@pranavk: हाँ, squareऔर &square(और, वास्तव में, *squareऔर **square) सभी एक ही फ़ंक्शन पॉइंटर का उल्लेख करते हैं।
जोनाथन लेफ्लर

6
@ user814628: यह स्पष्ट नहीं है कि आप क्या पूछ रहे हैं। के साथ typedef int newname, आप के newnameलिए एक उपनाम में बना रहे हैं int। के साथ typedef int (*func)(int), आप के funcलिए एक उपनाम में बना रहे हैं int (*)(int)- एक सूचक एक intतर्क लेने और एक intमान लौटाने के लिए कार्य करता है ।
जोनाथन लेफ़लर

10
मुझे लगता है कि मैं सिर्फ ऑर्डर को लेकर उलझन में हूं। टाइपडीफ के साथ int (*func)(int), मैं समझता हूं कि फंक एक उपनाम है, बस थोड़ा उलझन में है क्योंकि उपनाम प्रकार के साथ उलझ गया है। typedef int INTएक उदाहरण के रूप में जा रहा हूं तो मुझे और अधिक आसानी होगी यदि टाइपडेफ फ़ंक्शन पॉइंटर फॉर्म का था typedef int(*function)(int) FUNC_1। इस तरह मैं एक में जाली होने के बजाय दो अलग-अलग टोकन में प्रकार और उपनाम देख सकता हूं।
dhethetri

188
  1. typedefउपनाम प्रकार के लिए प्रयोग किया जाता है; इस मामले में आप के FunctionFuncलिए aliasing कर रहे हैं void(*)()

  2. वास्तव में वाक्यविन्यास अजीब लगता है, इस पर एक नज़र है:

    typedef   void      (*FunctionFunc)  ( );
    //         ^                ^         ^
    //     return type      type name  arguments
  3. नहीं, यह केवल संकलक को बताता है कि FunctionFuncप्रकार एक फ़ंक्शन पॉइंटर होगा, यह इस तरह से एक को परिभाषित नहीं करता है :

    FunctionFunc x;
    void doSomething() { printf("Hello there\n"); }
    x = &doSomething;
    
    x(); //prints "Hello there"

27
typedefएक नए प्रकार की घोषणा नहीं करता है । आपके पास typedefएक ही प्रकार के कई-अलग- अलग नाम हो सकते हैं , और वे अलग-अलग नहीं हैं (उदाहरण के लिए फ़ंक्शन के ओवरलोडिंग)। ऐसी कुछ परिस्थितियाँ हैं, जिनके संबंध में, आप नाम का उपयोग कैसे कर सकते हैं, इसके लिए एक- typedefनिर्धारित नाम बिलकुल उसी के समतुल्य नहीं है जो इसे परिभाषित किया गया है, लेकिन typedefउसी के लिए कई- अलग-अलग नाम समान हैं।
चीयर्स एंड हीथ। -

आह मैं अब समझ गया धन्यवाद।
5-28 पर जैक हार्विन

4
प्रश्न 2 के उत्तर के लिए +1 - बहुत स्पष्ट। बाकी के उत्तर भी स्पष्ट थे, लेकिन वह मेरे लिए खड़ा है :-)
माइकल वैन डेर वेस्टहुइज़न

33

typedefशब्द के बिना , C ++ में घोषणा बिना FunctionFuncकिसी तर्क के कार्य करने के लिए टाइप पॉइंटर के एक वैरिएबल की घोषणा करेगी , लौटकर void

इसके typedefबजाय यह FunctionFuncउस प्रकार के लिए एक नाम के रूप में परिभाषित करता है ।


5
यह उसके बारे में सोचने का एक बहुत अच्छा तरीका है। यदि आप अन्य उत्तरों को ध्यान से पढ़ते हैं, तो वे वास्तव में उर्फ ​​और नाम के उलझाव के बारे में ओपी के भ्रम को संबोधित नहीं करते हैं। मैंने इस पोस्ट को पढ़ने से कुछ नया सीखा।
मैड फिजिसिस्ट

9

यदि आप C ++ 11 का उपयोग कर सकते हैं तो आप उपयोग std::functionऔर usingकीवर्ड करना चाह सकते हैं ।

using FunctionFunc = std::function<void(int arg1, std::string arg2)>;

1
बिना C ++ 11 usingकीवर्ड की तरह होगा typedef std::function<void(int, std::string)> FunctionFunc;, बस किसी के मामले में C ++ 11 के बिना कार्यों के आसपास एक और आवरण चाहता है
टॉप-मास्टर

2
#include <stdio.h>
#include <math.h>

/*
To define a new type name with typedef, follow these steps:
1. Write the statement as if a variable of the desired type were being declared.
2. Where the name of the declared variable would normally appear, substitute the new type name.
3. In front of everything, place the keyword typedef.
*/

// typedef a primitive data type
typedef double distance;

// typedef struct 
typedef struct{
    int x;
    int y;
} point;

//typedef an array 
typedef point points[100]; 

points ps = {0}; // ps is an array of 100 point 

// typedef a function
typedef distance (*distanceFun_p)(point,point) ; // TYPE_DEF distanceFun_p TO BE int (*distanceFun_p)(point,point)

// prototype a function     
distance findDistance(point, point);

int main(int argc, char const *argv[])
{
    // delcare a function pointer 
    distanceFun_p func_p;

    // initialize the function pointer with a function address
    func_p = findDistance;

    // initialize two point variables 
    point p1 = {0,0} , p2 = {1,1};

    // call the function through the pointer
    distance d = func_p(p1,p2);

    printf("the distance is %f\n", d );

    return 0;
}

distance findDistance(point p1, point p2)
{
distance xdiff =  p1.x - p2.x;
distance ydiff =  p1.y - p2.y;

return sqrt( (xdiff * xdiff) + (ydiff * ydiff) );
}

1
किन परिस्थितियों में 'और' की आवश्यकता है? उदाहरण के लिए, 'func_p = & findDistance' और 'func_p = findDistance' समान रूप से काम करते हैं?
डोना

1
एक फ़ंक्शन नाम एक सूचक है, इसलिए आपको इसके साथ 'और' का उपयोग करने की आवश्यकता नहीं है। दूसरे शब्दों में, '&' वैकल्पिक है जब फ़ंक्शन पॉइंटर्स पर विचार किया जाता है। हालाँकि, आदिम डेटा प्रकार के लिए आपको इसका पता प्राप्त करने के लिए 'और' का उपयोग करना होगा।
अमजद

1
यह हमेशा इतना अजीब होता है कि 'और' कभी भी वैकल्पिक हो सकता है। अगर किसी टाइपिफ़ाइफ़ का उपयोग किसी आदिम (यानी typedef (*double) p, 'वैकल्पिक' के लिए पॉइंटर बनाने के लिए किया जाता है ?
डोना

मुझे लगता है कि आप typedef double* pएक पॉइंटर को डबल में परिभाषित करने के लिए टाइप करना चाहते थे । यदि आप pसूचक को एक आदिम चर से आबाद करना चाहते हैं , तो आपको 'और' का उपयोग करने की आवश्यकता होगी। एक ओर ध्यान दें, हम आपको * <पॉइंटर नाम> एक पॉइंटर को स्थगित करने के लिए। *समारोह सूचक सूचक (समारोह नाम) भिन्नता और स्मृति के ब्लॉक जहां समारोह निर्देश स्थित हैं पर जाने के लिए प्रयोग किया जाता है।
अमजद

2

वाक्यविन्यास के सामान्य मामले के लिए आप ANSI C मानक के अनुलग्नक A को देख सकते हैं ।

वहां से बैकस-नौर फॉर्म में, आप देख सकते हैं कि typedefइसका प्रकार है storage-class-specifier

प्रकार में declaration-specifiersआप देख सकते हैं कि आप कई निर्दिष्ट प्रकारों को मिला सकते हैं, जिनमें से कोई फर्क नहीं पड़ता।

उदाहरण के लिए, यह कहना सही है,

long typedef long a;

के लिए aएक उपनाम के रूप में प्रकार को परिभाषित करने के लिए long long। इसलिए, एग्जॉस्ट के उपयोग पर लिखे गए टाइफाइड को समझने के लिए आपको कुछ बैकस-नाउर फॉर्म से परामर्श करने की जरूरत है जो सिंटैक्स को परिभाषित करता है (एएनएसआई सी के लिए कई सही व्याकरण हैं, न केवल आईएसओ के)।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.