2010-05-04 19 views
5
int valid (int x, int y) { 
    return x + y; 
} 

int invalid (int x) { 
    return x; 
} 

int func (int *f (int, int), int x, int y) { 
    //f is a pointer to a function taking 2 ints and returning an int 
    return f(x, y); 
} 

int main() { 
    int val = func(valid, 1, 2), 
     inval = func(invalid, 1, 2); // <- 'invalid' does not match the contract 

    printf("Valid: %d\n", val); 
    printf("Invalid: %d\n", inval); 

    /* Output: 
    * Valid: 3 
    * Invalid: 1 
    */ 
} 

लाइन inval = func(invalid, 1, 2); पर की आवश्यकताओं से मेल नहीं खाता, मैं क्यों एक संकलक त्रुटि नहीं मिल रहा है के लिए एक सूचक पासिंग? यदि func एक पॉइंटर को 2 इंट्स लेने वाले फ़ंक्शन से अपेक्षा करता है और मैं एक फंक्शन को एक फंक्शन पास करता हूं जो एक इंट लेता है, तो संकलक शिकायत क्यों नहीं कर रहा है?एक समारोह है कि औपचारिक पैरामीटर

इसके अलावा, यह हो रहा है, फ़ंक्शन में दूसरे पैरामीटर y का क्या होता है?

+0

जिज्ञासा से बाहर ... उपरोक्त प्रोग्राम आउटपुट सही ढंग से करता है? – SysAdmin

+0

हां, ऐसा करता है ... यही कारण है कि मैंने वास्तव में पूछा। –

+1

क्या आप चेतावनियों के साथ संकलित हैं? –

उत्तर

1

आप चाहते हैं:

int func (int (*f) (int, int), int x, int y) { 

क्या आप अपने कोड में एक समारोह है कि एक पूर्णांक * रिटर्न के प्रकार है - आप एक समारोह है कि एक पूर्णांक रिटर्न के लिए सूचक चाहते हैं। कि परिवर्तन के साथ, इस लाइन:

inval = func(invalid, 1, 2); 

मुझे देता है:

fp.c:16: warning: passing argument 1 of 'func' from incompatible pointer type 
fp.c:9: note: expected 'int (*)(int, int)' but argument is of type 'int (*)(int)' 
जीसीसी के साथ

। आपके मूल कोड ने मुझे कई चेतावनियां भी दीं, बीटीडब्ल्यू - आप किस कंपाइलर का उपयोग कर रहे हैं? और यदि आपका प्रश्न वास्तव में है "यह कोड क्यों काम करता है?", ठीक है, यह अनिर्धारित व्यवहार की खुशी में से एक है।

+0

नील, क्या आप उस पर थोड़ी अधिक जानकारी दे सकते हैं? –

+0

आपने जो कहा वह इस अर्थ में सच है कि मेरे मामले में, 'f' एक फ़ंक्शन पर पॉइंटर के बजाए पॉइंटर लौटने वाला फ़ंक्शन है। लेकिन, यहां तक ​​कि जब मैंने इसे '(* एफ)' में बदल दिया, वहां भी कोड चलाने के संबंध में अभी भी कोई समस्या नहीं है। –

2

संकलक शिकायत क्यों नहीं कर रहा है?

शायद आपको एक बेहतर कंपाइलर चाहिए? जीसीसी इस कोड पर warning: passing argument 1 of ‘func’ from incompatible pointer type कहते हैं।

इसके अलावा, चूंकि यह हो रहा है, अमान्य फ़ंक्शन में दूसरे पैरामीटर y का क्या होता है?

शायद क्या होता है संकलक जो कुछ भी यह सामान्य रूप से एक पैरामीटर (,, आदि ढेर पर धक्का एक निर्दिष्ट रजिस्टर में डाल दिया) पारित करने के लिए क्या करना होगा करता है। पैरामीटर की गलत संख्या वाले फ़ंक्शन को कॉल करना अनिर्धारित व्यवहार है, हालांकि, कोई गारंटी नहीं है - प्रोग्राम क्रैश हो सकता है, या कंपाइलर monkeys fly out of your nose बना सकता है।

0

में दूसरे पैरामीटर वाई के साथ अमान्य फ़ंक्शन होता है?

संकलक अभी भी कोड है कि रेखा

return f(x, y); 

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

2

मान लिया जाये कि आप सभी संकलक चेतावनी को अनदेखा कर रहे है कि इस आप देना चाहिए, तुम क्या इस तरह होता है के बारे में सोच सकते हैं:

आपका कोड एक समारोह जो दो ints लेता है, और एक रिटर्न कॉल करने के लिए प्रयास कर रहा है।कॉलिंग कन्वेंशन के आधार पर पैरामीटर सीपीयू या स्टैक पर रजिस्टरों में पास किए जा सकते हैं, आउटपुट शायद एक रजिस्टर में जाता है। valid कॉल ठीक काम करता है, सब कुछ वह जगह है जहां इसकी उम्मीद है। invalid कॉल के लिए एक ही स्टैक को सेट किया गया है, दो पैरामीटर के साथ, जैसा कि प्रोग्राम सोचता है कि यह कॉलिंग है, तो फ़ंक्शन को कॉल किया जाता है।

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

अनियंत्रित आप यहां अपरिभाषित व्यवहार का आह्वान कर रहे हैं। एकल पैरामीटर फार्म के लिए func बदलते

int func(int(*f)(int),x){return f(x);} 

की कोशिश करो और अगर दोनों कॉल अभी भी काम देखते हैं।

1

एक उदाहरण है जहाँ अपरिभाषित व्यवहार काम करता है,
और शायद कुछ इसी तरह अपने उदाहरण में हो रहा है।

typedef int (*p)(int, int); 
typedef int (*p2)(int); 

int invalid (int x) { 
    return x; 
} 

int func() { 
    p2 f = invalid; 
    return ((p)f)(1, 2); 
} 

// IA32 asm, "func" 
... 
216:  p2 f = invalid; 
00402148 mov   dword ptr [ebp-4],offset @ILT+1380(invalid) (00401569) 
0040214F mov   eax,dword ptr [ebp-4] 
00402152 mov   dword ptr [ebp-4],eax 
217:  return ((p)f)(1, 2); 
00402155 mov   esi,esp 
00402157 push  2 ; <-- 
00402159 push  1 ; <-- 
0040215B call  dword ptr [ebp-4] ; "invalid" will use only "1" 
0040215E add   esp,8 ; <-- `pop` the arguments 
... 
0

सी में, यह एक प्रकार से दूसरे में एक सूचक को डालने में त्रुटि नहीं है। हालांकि, एक अच्छा संकलक बिना किसी स्पष्ट कलाकार के गलत पॉइंटर प्रकार को पारित करते समय चेतावनी उत्पन्न करेगा। अगर आपको कोई चेतावनी नहीं मिल रही है, तो मैं सुनिश्चित करता हूं कि चेतावनियां चालू हैं, यह सुनिश्चित करने के लिए मैं आपकी कंपाइलर सेटिंग्स की जांच करने की दृढ़ता से अनुशंसा करता हूं। या एक अलग संकलक का उपयोग करने पर विचार करें। ;-)

यह समझने के लिए कि यह क्यों काम करता है, आपको असेंबली भाषा के बारे में कुछ समझने की आवश्यकता है और कैसे सी पैरामीटर पास करने के लिए the stack का उपयोग करता है। आप प्लेटों के बड़े ढेर के रूप में ढेर को कल्पना कर सकते हैं, जहां प्रत्येक प्लेट में एक साधारण चर होता है। कई प्लेटफॉर्म पर, सभी पैरामीटर स्टैक पर पास किए जाते हैं। funcy और x को धक्का देगा, f पर कॉल करें, फिर चर को वापस बंद करें। valid स्टैक पर दो शीर्ष प्रविष्टियों को देखकर x और y लोड करता है। invalid स्टैक पर शीर्ष प्रविष्टि को देख कर x पाता है।

यहाँ ढेर के अंदर अवैध नज़र आ सकते हैं:

main:  3 
      uninitialized 
f:  2 
      1 
      invalid 
invalid: 2 
      1 

invalid() एक पैरामीटर लेता है, तो यह सिर्फ ढेर (1) और पैरामीटर के रूप में यह भार के शीर्ष पर लग रहा है।

यह भी printf काम जैसे कार्यों का काम करता है। वे पैरामीटर की एक चर संख्या स्वीकार कर सकते हैं। पहला पैरामीटर स्टैक के शीर्ष पर है, और वे केवल कई पैरामीटर के लिए स्टैक को देख सकते हैं। कुछ सिस्टम स्टैक का उपयोग करने के बजाय रजिस्टरों में कुछ पैरामीटर पास करते हैं, लेकिन यह समान रूप से काम करता है।

सी के शुरुआती दिनों में, फ़ंक्शन घोषणाओं में पैरामीटर शामिल नहीं थे। वास्तव में, यदि आप कोष्ठक के बीच कुछ भी बिना किसी फ़ंक्शन की घोषणा करते हैं, तो आप अभी भी एक फ़ंक्शन को परिभाषित कर सकते हैं।उदाहरण के लिए, यह सिर्फ ठीक संकलित:

void foo(); 
void bar(void) { 
     foo(5); /* foo's parameters are implicit */ 
} 

इसलिए यह जब पैरामीटर के बिना एक समारोह की घोषणा void शामिल करने के लिए महत्वपूर्ण है। यह संकलक को बताता है कि फ़ंक्शन वास्तव में नहीं पैरामीटर लेता है। कोष्ठक के बीच कुछ भी नहीं के साथ, यह अंतर्निहित पैरामीटर के साथ एक समारोह है।

+0

"पैरामीटर के साथ फ़ंक्शन घोषित करते समय शून्य शामिल करें।" - मुझे लगता है कि आप "पैरामीटर के बिना" मतलब है। –

+1

@ एंड्रियास फिक्स्ड, धन्यवाद! –

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