2015-06-30 4 views
5

पर पुन: प्रयास करना यह प्रश्न परीक्षण उद्देश्यों के लिए है, और कुछ नहीं।शून्य (*)() को फ़ंक्शन पॉइंटर कास्टिंग, फिर मूल प्रकार

मैं वर्तमान में फ़ंक्शन पॉइंटर्स को विभिन्न पैरामीटर के साथ स्टोर करने की कोशिश कर रहा हूं (और इन पैरामीटर में विभिन्न प्रकार हो सकते हैं)।

असल में, मैं सी ++ 11 में निम्न कोड स्निपेट कोड जोड़ने के बाद:

#include <functional> 
#include <iostream> 

void fct(int nb, char c, int nb2, int nb3) { 
    std::cout << nb << c << nb2 << nb3 << std::endl; 
} 

template <typename... Args> 
void call(void (*f)(), Args... args) { 
    (reinterpret_cast<void(*)(Args...)>(f))(args...); 
} 

int main(void) { 
    call(reinterpret_cast<void(*)()>(&fct), 42, 'c', 19, 94); 
} 

मैं एक सामान्य void(*)() समारोह सूचक में एक void(*)(int, char, int, int) समारोह सूचक परिवर्तित। फिर, वैरैडिक टेम्पलेट पैरामीटर का उपयोग करके, मैं बस फ़ंक्शन पॉइंटर को अपने मूल प्रकार में पुन: प्रस्तुत करता हूं और फ़ंक्शन को कुछ पैरामीटर के साथ कॉल करता हूं।

यह कोड संकलित करता है और चलाता है। ज्यादातर बार, यह अच्छे मूल्य प्रदर्शित करता है। हालांकि, यह कोड मुझे मैक ओएस (अनियमित मानों के संबंध में) के तहत कुछ Valgrind त्रुटियां देता है और यह कभी-कभी कुछ अप्रत्याशित कचरा प्रदर्शित करता है।

==52187== Conditional jump or move depends on uninitialised value(s) 
==52187== at 0x1004E4C3F: _platform_memchr$VARIANT$Haswell (in /usr/lib/system/libsystem_platform.dylib) 
==52187== by 0x1002D8B96: __sfvwrite (in /usr/lib/system/libsystem_c.dylib) 
==52187== by 0x1002D90AA: fwrite (in /usr/lib/system/libsystem_c.dylib) 
==52187== by 0x100025D29: std::__1::__stdoutbuf<char>::overflow(int) (in /usr/lib/libc++.1.dylib) 
==52187== by 0x10001B91C: std::__1::basic_streambuf<char, std::__1::char_traits<char> >::xsputn(char const*, long) (in /usr/lib/libc++.1.dylib) 
==52187== by 0x10003BDB0: std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > std::__1::__pad_and_output<char, std::__1::char_traits<char> >(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, char const*, char const*, char const*, std::__1::ios_base&, char) (in /usr/lib/libc++.1.dylib) 
==52187== by 0x10003B9A7: std::__1::num_put<char, std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > >::do_put(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, std::__1::ios_base&, char, long) const (in /usr/lib/libc++.1.dylib) 
==52187== by 0x1000217A4: std::__1::basic_ostream<char, std::__1::char_traits<char> >::operator<<(int) (in /usr/lib/libc++.1.dylib) 
==52187== by 0x1000011E8: fct(int, char, int, int) (in ./a.out) 
==52187== by 0x1000013C2: void call<int, char, int, int>(void (*)(), int, char, int, int) (in ./a.out) 
==52187== by 0x100001257: main (in ./a.out) 

मुझे यह बहुत उत्सुक लगता है क्योंकि जब मैं फ़ंक्शन को कॉल करता हूं, तो मैंने फ़ंक्शन पॉइंटर को अपने मूल प्रकार में दोबारा दर्ज किया है। मैंने सोचा कि यह void* पर डेटाटाइप कास्टिंग करने के समान था और फिर इसे मूल डेटाटाइप में पुन: स्थापित कर रहा था।

मेरे कोड में क्या गलत है? क्या हम फ़ंक्शन पॉइंटर्स को void(*)() पॉइंटर पर नहीं डाल सकते हैं और फिर इस पॉइंटर को मूल फ़ंक्शन पॉइंटर हस्ताक्षर में पुन: प्रस्तुत कर सकते हैं?

यदि नहीं, तो क्या यह हासिल करने के कुछ अन्य तरीके हैं? मुझे std::bind में कोई दिलचस्पी नहीं है जो मैं नहीं चाहता हूं।

+0

आपका मतलब फ़ंक्शन पॉइंटर्स है? सदस्य कार्यों के लिए संकेतक नहीं है? – MSalters

+1

मैं इसे पुन: उत्पन्न नहीं कर सकता। क्या यह आपका वास्तविक, शाब्दिक परीक्षण मामला है? –

+0

हां, यह वही कोड है जो मैंने चलाया है (मैकोस योसमेट पर)। इसके अलावा, अगर मैं एक अंतिम std :: स्ट्रिंग द्वारा अंतिम पैरामीटर को प्रतिस्थापित करता हूं, तो मुझे कचरा मिला। –

उत्तर

1

एक अंग पर बाहर जा रहे हैं और अनुमान लगा क्या आप इसे विफल करने के लिए किया था ...

#include <functional> 
#include <iostream> 

void fct(int nb, char c, int nb2, std::string nb3) { 
    std::cout << nb << c << nb2 << nb3 << std::endl; 
} 

template <typename... Args> 
void call(void (*f)(), Args... args) { 
    (reinterpret_cast<void(*)(Args...)>(f))(args...); 
} 

int main(void) { 
    call(reinterpret_cast<void(*)()>(&fct), 42, 'c', 19, "foobar"); 
} 

यह असफल हो जायेगी क्योंकि "foobar" कभी नहीं std::string में परिवर्तित हो जाता ... कैसे संकलक अगर पता कर सकते हैं यह Args... के माध्यम से चला जाता है?

मुझे यकीन नहीं है कि कैसे std::string कॉलर द्वारा कॉल स्टैक पर धक्का दिया जाता है (एक स्ट्रिंग संदर्भ पॉइंटर के रूप में धक्का दिया जाएगा), लेकिन मुझे संदेह है कि यह char* पर केवल एक ही सूचक से अधिक है। जब कैली उस पॉइंटर को char* पर पूरे string सदस्य की अपेक्षा करता है, तो यह बाहर निकलता है।

मुझे लगता है कि अगर आप

void fct(int nb, char c, int nb2, char* nb3) 

या

call(reinterpret_cast<void(*)()>(&fct), 42, 'c', 19, std::string("foobar")); 

तो यह पराक्रम काम करने के लिए बदल जाते हैं।

+1

तार्किक! आपके विवरण के लिए धन्यवाद। यह देखने के लिए एक अच्छा विचार हो सकता है कि विविधता सूची कैसे प्रबंधित की जाती है। मुझे लगता है कि मैकोज़क्स पर वालग्रिंड के अस्थिर कार्यान्वयन के कारण मुझे मिली वाल्ग्रिंड त्रुटि मिली है। –

1

आपने कहा कि आप वैकल्पिक कार्यान्वयन में भी रुचि रखते हैं। व्यक्तिगत रूप से, मैं इस तरह से चीजों को लागू नहीं करता, भले ही यह पूरी तरह से काम करता है, दोनों फ़ंक्शन पॉइंटर्स और reinterpret_casts वे चीजें हैं जिन्हें मैं टालने का प्रयास करता हूं। मैं इस कोड का परीक्षण किया है नहीं है, लेकिन मेरे विचार होगा:

#include <functional> 
#include <iostream> 
#include <boost/any.hpp> 

template <typename... Args> 
void call(boost::any clbl, Args... args) { 
    auto f = boost::any_cast<std::function<void(Args...)>>(clbl); 
    f(args...); 
} 

int main(void) { 
    std::function<void(int, char, int, int)> func = fct; 
    call(boost::any(func), 42, 'c', 19, 94); 
} 

संपादित करें: इस कोड, नि: शुल्क विज्ञापन की अपनी परिभाषा के साथ संयुक्त, सही ढंग से काम करता है, और फेडोरा पर valgrind के तहत स्वच्छ चलाता है, clang35 साथ संकलित।

+1

कोड स्पष्ट है, लेकिन मुझे लगता है कि यह केवल reinterpret_cast को छुपाता है (जो निश्चित रूप से बूस्ट :: any_cast कार्यान्वयन में आंतरिक रूप से किया जाता है)। हालांकि, आपके उदाहरण के लिए धन्यवाद, मैंने अभी तक boost :: any और boost :: any_cast के बारे में नहीं सुना है! –

+1

यह वास्तव में आंतरिक रूप से एक static_cast है। बूस्ट :: यहां तक ​​कि किसी भी गतिशील कलाकार का आंतरिक रूप से उपयोग करने वाले संस्करण भी हैं ... यदि आप गड़बड़ करते हैं तो एक सेगफॉल्ट के बजाय अपवाद प्राप्त करने के लिए बहुत अच्छा है। –

+0

जानना अच्छा है, धन्यवाद! –

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