क्यों फ़ंक्शन पॉइंटर परिभाषाएँ किसी भी संख्या में एम्परसेंड्स 'और' या तारांकन '*' के साथ काम करती हैं?


216

निम्नलिखित कार्य क्यों करते हैं?

void foo() {
    cout << "Foo to you too!\n";
};

int main() {
    void (*p1_foo)() = foo;
    void (*p2_foo)() = *foo;
    void (*p3_foo)() = &foo;
    void (*p4_foo)() = *&foo;
    void (*p5_foo)() = &*foo;
    void (*p6_foo)() = **foo;
    void (*p7_foo)() = **********************foo;

    (*p1_foo)();
    (*p2_foo)();
    (*p3_foo)();
    (*p4_foo)();
    (*p5_foo)();
    (*p6_foo)();
    (*p7_foo)();
}

जवाबों:


224

इसके लिए कुछ टुकड़े हैं जो इन सभी संचालकों को समान तरीके से काम करने की अनुमति देते हैं।

इन सभी कार्यों का मूल कारण यह है कि एक फ़ंक्शन (जैसे foo) फ़ंक्शन के लिए एक सूचक के लिए अनुमानित रूप से परिवर्तनीय है। यही कारण है कि void (*p1_foo)() = foo;काम करता है: fooअंतर्निहित रूप से एक सूचक में खुद को बदल दिया जाता है और उस सूचक को सौंपा जाता है p1_foo

&जब एक फ़ंक्शन पर लागू किया जाता है, तो यूनरी फ़ंक्शन को पॉइंटर देता है, जैसे कि यह किसी ऑब्जेक्ट के पते को उत्पन्न करता है जब इसे किसी ऑब्जेक्ट पर लागू किया जाता है। साधारण कार्यों के संकेत के लिए, यह अंतर्निहित फ़ंक्शन-टू-फ़ंक्शन-पॉइंटर रूपांतरण के कारण हमेशा बेमानी है। किसी भी मामले में, यही कारण है कि void (*p3_foo)() = &foo;काम करता है।

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

इन नियमों को जोड़ा जा सकता है। अपने दूसरे से अंतिम उदाहरण पर विचार करें **foo:

  • सबसे पहले, fooसंक्षेप में खुद को एक पॉइंटर में बदल दिया जाता है और पहले *उस फ़ंक्शन पॉइंटर पर लागू किया जाता है, fooफिर से फ़ंक्शन को पैदावार देता है ।
  • फिर, परिणाम को फिर से एक सूचक में स्वयं में बदल दिया जाता है और दूसरा *लागू किया जाता है, फिर से समारोह में उपज foo
  • इसके बाद इसे फिर से फंक्शन पॉइंटर में बदल दिया जाता है और वेरिएबल को असाइन किया जाता है।

आप जितने चाहें उतने जोड़ सकते हैं *, परिणाम हमेशा एक जैसा होता है। अधिक *एस, मर्जर।

हम आपके पांचवें उदाहरण पर भी विचार कर सकते हैं &*foo:

  • सबसे पहले, fooसंक्षेप में खुद को एक सूचक में बदल दिया जाता है; यूरी *को fooफिर से लागू किया जाता है ।
  • फिर, एक पॉइंटर को पैदावार &करने के लिए लागू किया fooजाता है foo, जिसे चर को सौंपा गया है।

&केवल हालांकि, एक समारोह है कि एक समारोह सूचक में बदल दिया गया (नहीं एक समारोह को लागू किया जा सकता है जब तक, ज़ाहिर है, समारोह सूचक एक चर, जिस स्थिति में परिणाम एक सूचक-टु-ए-pointer- है एक समारोह में, उदाहरण के लिए, आप अपनी सूची में जोड़ सकते हैं void (**pp_foo)() = &p7_foo;)।

यही कारण है कि &&fooकाम नहीं करता है: &fooएक कार्य नहीं है; यह एक फंक्शन पॉइंटर है जो एक रव्यू है। हालाँकि, &*&*&*&*&*&*fooकाम करेगा, जैसा कि होगा &******&foo, क्योंकि उन दोनों अभिव्यक्तियों में &हमेशा एक फ़ंक्शन पर लागू किया जाता है, न कि किसी फ़ंक्शन फ़ंक्शन सूचक के लिए।

यह भी ध्यान दें कि आपको *फ़ंक्शन पॉइंटर के माध्यम से कॉल करने के लिए यूनिरी का उपयोग करने की आवश्यकता नहीं है ; दोनों (*p1_foo)();और (p1_foo)();एक ही परिणाम है, फिर से फ़ंक्शन-टू-फ़ंक्शन-पॉइंटर रूपांतरण के कारण।


2
@ जिमी: वे फ़ंक्शन पॉइंटर्स के संदर्भ नहीं हैं, वे केवल फ़ंक्शन पॉइंटर्स हैं। &fooपता चलता है foo, जिसके परिणामस्वरूप एक फ़ंक्शन पॉइंटर इंगित होता है foo, जैसा कि कोई अपेक्षा करता है।
डेनिस ज़िकफोज़ 0

2
आप &ऑब्जेक्ट के लिए ऑपरेटरों को चेन नहीं कर सकते हैं: दिया गया है int p;, &pएक पॉइंटर को पैदावार देता है pऔर एक प्रतिद्वंद्विता अभिव्यक्ति है; &ऑपरेटर एक lvalue अभिव्यक्ति की आवश्यकता है।
जेम्स मैकनेलिस

12
मैं असहमत हूं। अधिक है *, कम मीरा
सेठ कार्नेगी

28
कृपया मेरे उदाहरणों के वाक्य-विन्यास को संपादित न करें। मैंने विशेष रूप से भाषा की विशेषताओं को प्रदर्शित करने के लिए उदाहरणों को चुना है।
जेम्स मैकनेलिस

7
एक साइड नोट के रूप में, सी मानक स्पष्ट रूप से बताता है कि एक &*दूसरे को रद्द करने का एक संयोजन (6.5.3.2): "The unary & operator yields the address of its operand."/ - / "If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue."
लुंडिन

9

मुझे लगता है कि यह याद रखना भी मददगार है कि सी अंतर्निहित मशीन के लिए सिर्फ एक अमूर्त है और यह उन जगहों में से एक है जहां अमूर्त रिसाव हो रहा है।

कंप्यूटर के दृष्टिकोण से, एक फ़ंक्शन सिर्फ एक मेमोरी एड्रेस है, जिसे निष्पादित किया जाता है, तो अन्य निर्देश निष्पादित करता है। तो C में एक फ़ंक्शन को स्वयं एक पते के रूप में मॉडल किया गया है, जो संभवतः इस डिज़ाइन की ओर जाता है कि एक फ़ंक्शन "समान" है क्योंकि पता उसी बिंदु पर है।


0

&और *C में एक फ़ंक्शन के रूप में घोषित एक प्रतीक पर बेतुका संचालन हैं func == *func == &func == *&funcऔर इसलिए इसका मतलब है*func == **func

इसका मतलब है कि प्रकार int ()के रूप में ही है int (*)()एक समारोह पैरामीटर और एक परिभाषित समारोह के रूप में पारित किया जा सकता के रूप में *func, funcया &func(&func)()के रूप में ही है func()गॉडबोल्ट लिंक।

एक समारोह वास्तव में, एक पता है इसलिए *और &कोई अर्थ नहीं है, और एक त्रुटि का निर्माण करने के बजाय, संकलक चुनता समारोह का पता के रूप में यह व्याख्या करने के लिए।

&प्रतीक एक समारोह सूचक के रूप में घोषित पर फिर भी (क्योंकि यह अब एक अलग उद्देश्य है) सूचक का पता मिल जाएगा, जबकि funcpऔर *funcpसमान होगा

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