2008-11-03 13 views
6

सी में qsort का उपयोग करके हम एक तुलना फ़ंक्शन में पास करते हैं उदा।सी - एड्रेस ऑपरेटर "अनावश्यक" में फ़ंक्शन पॉइंटर्स

int cmp(const void*, const void*); 

qsort की protoype एक पूर्णांक (*) (स्थिरांक शून्य *, स्थिरांक शून्य *) की उम्मीद है तो हम कहते हैं:

qsort(..., cmp); 

लेकिन यह कॉल करने के लिए समान रूप से मान्य है:

qsort(..., &cmp); 

और अगर हम सी ++ में स्थिर सदस्य-फ़ंक्शन में पास हुए तो हमें यही करना होगा। Kernighan & रिची (द्वितीय संस्करण, 5.11 "पॉइंटर्स टू फ़ंक्शंस" p119) कहता है कि "चूंकि [cmp] को फ़ंक्शन होने के लिए जाना जाता है, & ऑपरेटर आवश्यक नहीं है, उसी तरह से इसे किसी सरणी नाम से पहले आवश्यक नहीं है। "

क्या कोई और इस के साथ थोड़ा असहज महसूस करता है (esp। टाइप-सुरक्षा के संबंध में)?

उत्तर

8

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

int main() 
{ 
    int integer = 0xFFFFFF; 
    void (*functionPointer)() = (void(*)())integer; 

    functionPointer(); 

    return 0; 
} 

यह संकलन समय पर पूरी तरह से मान्य है, लेकिन यह स्पष्ट रूप से सुरक्षित नहीं है।

+3

यह सच है, लेकिन यह है कि कलाकारों का उपयोग कर मारना संकलक बताने के लिए कि "मुझ पर भरोसा है, मैं जानता हूँ कि मैं क्या कर रहा हूं, भले ही आप अन्यथा लगता है कि"। –

3

यह एक वाक्यविन्यास विवरण है। यदि आप फ़ंक्शन पॉइंटर को इंगित करने के लिए & का उपयोग नहीं करना चाहते हैं तो हमेशा इसका उपयोग करें। यदि आप अतिरिक्त कीप्रेस को सहेजना चाहते हैं और अपने कोडिंग में स्पष्ट नहीं हैं तो इसका लाभ उठाएं।

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

यदि आप सी ++ का उपयोग कर रहे हैं, तो मैं सुझाव देता हूं कि बूस्ट फ़ैक्टर को किसी भी तरह से कार्य करने के लिए एक अच्छी विधि के रूप में देखें। ये सुंदर इकाइयां सी ++ में सभी कार्यों के लिए एक एकीकृत और काफी स्पष्ट वाक्यविन्यास की अनुमति देती हैं :)

1

वैध-अभी-विरोधाभासी वाक्यविन्यास विकल्पों के लिए विचलन के रूप में असुविधा की भावना इतनी अधिक नहीं है। या तो cmp पॉइंटर है, और इस तरह लगातार इलाज किया जाना चाहिए, या यह किसी अन्य प्रकार का है - जो, आईएमएचओ वाक्य रचनात्मक रूप से भ्रामक है।

थोड़ा आगे जा रहे हैं, मैं भी संकेतक भिन्नता या तो के लिए एक कॉल की आवश्यकता होगी (तथ्य यह है कि यह एक सूचक है उजागर करने के लिए) या नहीं (क्योंकि एक समारोह नाम एक सूचक है) ... लेकिन अनुमति नहीं दोनों।

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

4

मुझे संदेह है कि आपको केवल असहज महसूस होता है क्योंकि आपको सी के रूप में 'धातु के नजदीक' के रूप में कोडिंग करने के लिए उपयोग नहीं किया जाता है। कारणों पर सी को ऑपरेटर के पते पर ऑपरेटर की आवश्यकता नहीं है, इसका कारण यह है कि आप उन्हें कॉल करने या उन्हें पास करने के अलावा अन्य कार्यों के साथ वास्तव में कुछ भी नहीं कर सकते हैं।

दूसरे शब्दों में, वहाँ एक समारोह का 'मान' जोड़ तोड़ के लिए कोई समझदार परिभाषा है।

जबकि ints के साथ, आप करने के लिए जोड़ सकते हैं या मूल्य से घटाना कर सकते हैं, इस कार्य के लिए कोई मतलब नहीं है।

किसी भी मामले में, सी सी ++ और इसके अपने मानकीकरण दोनों को पूर्ववत करता है - मूल के & आर सी में प्रोटोटाइप भी नहीं थे और एएनएसआई को यह सुनिश्चित करना था कि उनके मानकीकरण ने जितना संभव हो सके मौजूदा कोड को तोड़ दिया नहीं है।

+1

यकीन है कि वहाँ है। आप functionptr ++ कर सकते हैं और स्टैक पर खराब, बुरी चीजें कर सकते हैं। ;) –

1

नोट है कि एक ही 'अपसंदर्भन' (अर्थात कॉल करना) समारोह संकेत के लिए चला जाता है, आप

funcptr(arg1, arg2); 

पर्याप्त होगा के रूप में

(*funcptr)(arg1, arg2); 

की जरूरत नहीं है।

5

खैर, जवाब है कि मूल्य द्वारा एक समारोह गुजर पैदावार एक समारोह सूचक, मूल्य से एक सरणी गुजर के रूप में एक ही तरह से अपनी पहली तत्व के लिए सूचक पैदावार है। एक कहता है कि सरणी और कार्य "क्षय"। केवल कुछ मौके हैं जहां वह क्षय नहीं होता है। उदाहरण के लिए आकार (सरणी) सरणी के आकार को उत्पन्न करता है, न कि इसके पहले तत्व सूचक में से एक। sizeof (फ़ंक्शन) अमान्य है (फ़ंक्शन कोई ऑब्जेक्ट नहीं हैं), आपको आकार (& फ़ंक्शन) करना होगा। अन्य अवसरों के संदर्भ के लिए बाध्य कर रहे हैं:

void baz(); 

void foo(void (&bar)()) { 
    bar(); 
} 

// doesnt work, since a reference to a function is requested. 
// you have to pass 'bar' itself, without taking its address 
// explicitely. 
foo(&baz); 

यह है, btw सब कारण है कि आप

template<typename T, int N> 
void ByRef(T (&foo)[N]) { 
    ... 
} 

कर सकते हैं के बाद से अभी तक सरणी क्षय नहीं करता जब संदर्भ मानकों पर विचार है।

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