2016-12-01 17 views
6

मैं एक समारोह सूचक समारोह जिसका char * यह arguments.Into उम्मीद के रूप में घोषित किया गया है, मैं करना चाहते हैं char const* तर्क लेने के रूप में घोषित एक समारोह में एक सूचक को बचाओ।पासिंग `पूर्णांक (*) (चार स्थिरांक *)` जहां `पूर्णांक (*) (चार *)` उम्मीद है

मुझे लगता है कि मैं एक आवरण या एक डाली उपयोग कर सकते हैं। निर्मोक और अधिक सरल लगता है, लेकिन मैं कानूनी तौर पर इस तरह के एक समारोह सूचक कलाकारों का परिणाम कॉल कर सकते हैं?

उदाहरण नीचे दिए गए कोड:

static int write_a(char * X){ 
    return 0; 
} 

static int write_b(char const* X){ 
    return 0; 
} 
static int wrapped_write_b(char * X){ 
    return write_b(X); 
} 

typedef int (*write_fn)(char *); 

write_fn a = write_a; 
write_fn b = wrapped_write_b; 
write_fn b1 = (write_fn)write_b; //is b1 legally callable? 
+5

[इस] के अनुसार (http://stackoverflow.com/a/559671/669576) यह यूबी (मुझे लगता है) है। हालांकि, जैसा कि 'कॉन्स' केवल बिल्ड-टाइम पर रन-टाइम पर लागू होता है, मुझे नहीं लगता कि यह एक समस्या होगी। –

+0

@ दांह: कलाकार पूरी तरह से कानूनी है। आपके द्वारा प्रदान किया गया लिंक इस कलाकार से बिल्कुल संबंधित नहीं है। – AnT

उत्तर

3

सच पूछिये तो, यह अनुमति नहीं है।

एक pointer-to-something एक pointer-to-qualified-something साथ संगत नहीं है। क्योंकि एक pointer-to-qualified-somethingpointer-to-something

ही के एक योग्य प्रकार नहीं है के लिए

pointer-to-function-accepting-something

और

pointer-to-function-accepting-qualified-something लागू होता है।

यह सी 11 के माध्यम से पाया जा सकता है 6.2.7 संगत के प्रकार:

दो प्रकार संगत प्रकार है अगर उनके प्रकार एक ही हैं। है कि क्या दो प्रकार का निर्धारण करने के लिए अतिरिक्त नियम संगत प्रकार क्वालिफायर के लिए प्रकार विनिर्देशक के लिए 6.7.2 में वर्णित हैं 6.7.3 में, रहे हैं ...

कहाँ 6.7.3 प्रासंगिक हिस्सा है। यह कहता है

दो योग्य प्रकारों के अनुकूल होने के लिए, दोनों के पास एक संगत प्रकार का समान रूप से योग्य संस्करण होगा;

रूपांतरण अध्याय 6.3.2.3 इस खंडन नहीं करता है:

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

संपादित

होल्ट ने जवाब में बताया गया है, दो कार्यों की अनुकूलता को स्पष्ट रूप से 6.7.6.3/15 में वर्णित है।


मुझे अभी भी लगता है कि एक रैपर फ़ंक्शन सबसे अच्छा समाधान है। समस्या की जड़ यह है कि write_a कॉन्स्ट-सही नहीं है। यदि आप उस फ़ंक्शन को नहीं बदल सकते हैं, तो उसके चारों ओर एक रैपर लिखें।

+0

कलाकार स्वयं पूरी तरह से अनुमति और कानूनी है। "अनुमति नहीं है" क्या है 'फ़ंक्शन को' बी 1 'के माध्यम से कॉल कर रहा है। लेकिन ओपी का कोड 'बी 1' के माध्यम से कोई कॉल नहीं करता है। – AnT

+0

इसके अलावा, "सख्त अलियासिंग" टिप्पणी यहां अप्रासंगिक है। * एलियासिंग * (और * सख्त एलियासिंग *) की अवधारणा केवल डेटा के पॉइंटर्स पर लागू होती है, न कि फ़ंक्शंस को इंगित करने के लिए। – AnT

+0

@ एएनटी आपकी पहली टिप्पणी के बारे में, यह वही है जो बोल्ड टेक्स्ट कहता है। आप सख्त एलियासिंग के बारे में सही हैं, मानक केवल वस्तुओं का उल्लेख करता है। फिक्स्ड। – Lundin

10

इस अपरिभाषित व्यवहार है - आप एक और प्रकार केवल तभी प्रकार के होते हैं संगत (6.3.2.3/8) के एक समारोह कॉल करने के लिए एक सूचक का उपयोग कर सकते हैं:

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

दो कार्यों में संगत प्रकार यदि (सरलीकृत संस्करण) वे एक ही मुनाफा होता है और तर्क संगत हैं (6.7.6.3, अर्थ विज्ञान/15): दो समारोह प्रकार संगत होना

के लिए, दोनों करेगा संगत रिटर्न प्रकार निर्दिष्ट करें .146) इसके अलावा, पैरामीटर प्रकार सूचियां, यदि दोनों मौजूद हैं, तो पैरामीटर की संख्या और इलिप्सिस टर्मिनेटर के उपयोग में सहमत होंगे; संबंधित पैरामीटर में संगत प्रकार होंगे।

एक const char * एक char * साथ संगत नहीं है (6.7.6.1, अर्थ विज्ञान/2): दो सूचक प्रकार संगत होना

के लिए, दोनों हूबहू योग्य होगा और दोनों संगत की ओर इशारा किया जाएगा प्रकार के।

के बाद से const char * और char * हूबहू योग्य नहीं हैं, वे संगत नहीं हैं, और b के माध्यम से write_b बुला अपरिभाषित व्यवहार है।

+0

कोई समस्या नहीं है। धन्यवाद। – PSkocik

+0

"आप फ़ंक्शन को कॉल करने के लिए पॉइंटर का उपयोग कर सकते हैं ..." लेकिन ओपी का कोड * बी 1' के माध्यम से * कॉल * कॉल नहीं करता है! – AnT

2

write_fn b1 = (write_fn) write_b; // क्या यह कानूनी है?

क्या कानूनी है?

इस कलाकार में शामिल फ़ंक्शन पॉइंटर प्रकार संगत नहीं हैं।

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

इस बीच, b1 के माध्यम से फ़ंक्शन को कॉल करने का प्रयास करने के परिणामस्वरूप अनिर्धारित व्यवहार होगा, विशेष रूप से क्योंकि सूचक प्रकार वास्तविक फ़ंक्शन प्रकार के साथ संगत नहीं है।

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

+0

अच्छा बिंदु। उस सूचक के माध्यम से फ़ंक्शन को कॉल करना एक लक्ष्य था जिसे मुझे स्पष्ट रूप से उल्लेख किया जाना चाहिए था। – PSkocik

+0

रेफरी जोड़ने का सुझाव दें: सी 11 §6.3.2.3 8 "एक प्रकार के किसी फ़ंक्शन के लिए पॉइंटर को किसी अन्य के फ़ंक्शन में एक पॉइंटर में परिवर्तित किया जा सकता है, फिर से वापस और पीछे; परिणाम मूल पॉइंटर के बराबर की तुलना करेगा।" – chux

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