2011-02-01 18 views
9

मिश्रित सी/सी ++ प्रोजेक्ट में ओवरलोड रिज़ॉल्यूशन, हमें सी से सी ++ फ़ंक्शन में कॉल करने की आवश्यकता है। कहा जाने वाला फ़ंक्शन तीन अलग-अलग कार्यों के रूप में अधिभारित होता है, लेकिन हम इसे सी-साइड से अनदेखा कर सकते हैं, हम केवल सबसे उपयुक्त चुनते हैं और उस पर चिपके रहते हैं।बाहरी "सी" लिंकेज

ऐसा करने के दो तरीके हैं: (1) एक बाहरी सी ++ रैपर को बाहरी "सी" फ़ंक्शन के साथ लिखें जो बाद में अधिभारित फ़ंक्शन को कॉल करता है, या (2) केवल एक फ़ंक्शन घोषित करने के लिए हैकिश तरीका सी से बाहरी "सी" के रूप में कॉल करना चाहते हैं।

सवाल यह है कि क्या दूसरे संस्करण के लिए जाने के लिए कोई नुकसान है (दुःस्वप्न और बुरे कर्म के अलावा)? दूसरे शब्दों में, तीन अधिभारित फ़ंक्शन दिया गया है, जहां किसी को "सी" के रूप में घोषित किया जाता है, क्या हमें सी ++ पक्ष के साथ परेशानी की उम्मीद करनी चाहिए, या क्या यह मानक के अनुसार अच्छी तरह परिभाषित है?

+3

कोड कोड गंध के समाधान का वर्णन करने के लिए "हैकिश" शब्द का उपयोग नहीं कर रहा है? –

+0

हां यह निश्चित रूप से एक कोड गंध है, मेरे एक कॉलेग्यू ने मुझे इसके बारे में पूछा और मैंने समाधान 1 करने की सिफारिश की क्योंकि मुझे लगता है कि यह क्लीनर है। लेकिन साथ ही, अगर हम समाधान 2 के लिए गए तो क्या होता है, इसके बारे में मुझे उत्सुकता है ... तथ्य यह है कि हमें पूछना है कि एक कम अनिश्चित समाधान मौजूद होने पर पहले से ही कोड गंध है :) – harald

उत्तर

14

मैंने कहा था कि यह अपरिभाषित था, लेकिन मानक को फिर से पढ़ना, मुझे वह भाषा नहीं मिल रही जो मैंने सोचा था। वास्तव में, §7.5/3 पर उदाहरण कोड इंगित करता है कि परिणाम शायद परिभाषित किया गया है - यानी, आप सी ++ लिंकेज के साथ अन्य ओवरलोड कर सकते हैं, जब तक कि "सी" लिंकेज के साथ केवल एक ही कार्य हो। उदाहरण वे दिखाते हैं:

complex sqrt(complex); // C + + linkage by default 
extern "C" { 
    double sqrt(double); // C linkage 
} 

दो बिंदु: 1) उदाहरण होने के नाते, यह मानक नहीं है। 2) यह सीधे यह नहीं बताता है कि दोनों घोषणाओं को वास्तव में एक ही कार्यक्रम में एक साथ अनुमति दी जाती है। फिर भी, मुझे लगता है कि इरादा यह है कि इसे कोड के एक टुकड़े के रूप में देखा जा सकता है जो परिभाषित व्यवहार देता है।

पुन: पढ़ने के बाद, मेरा मानना ​​है कि मानक में भाषा विशेष रूप से "सी" लिंकेज के साथ एक समारोह को अनुमति देने के लिए लिखी जाती है, और "सी ++" लिंक के साथ अन्य कार्यों की अनियंत्रित संख्या जो समान नाम को ओवरलोड करती है (§7.5/6):

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

+0

क्या आप मानक उद्धृत कर सकते हैं? – neuro

+0

धन्यवाद, मुझे अभी भी लगता है कि भविष्य में भ्रम से बचने के लिए मैं रैपर की सिफारिश करूंगा। – harald

+0

@harald: मैं निश्चित रूप से उस क्लीनर पर विचार करता हूं। –

2

यह मानक द्वारा अनुमति दी गई थी यहां तक ​​कि अगर, कोड के भविष्य देखरेख शायद बेहद उलझन में हो जाएगा और यहां तक ​​कि, extern "सी" को निकाल सकते हैं सी कोड (संभवतः काफी दूर तक बाद में है कि घटनाओं को तोड़ने नहीं हैं लिंक करने योग्य)।

बस रैपर लिखें।

संपादित करें: सी ++ 03 7.5/5 से:

तो एक ही समारोह या वस्तु के दो घोषणाओं अलग लिंकेज विनिर्देशों निर्दिष्ट (जो है, इन घोषणाओं के लिंकेज विनिर्देशों निर्दिष्ट अलग स्ट्रिंग अक्षर), प्रोग्राम खराब गठित होता है यदि घोषणाएं उसी अनुवाद इकाई में दिखाई देती हैं, और एक परिभाषा नियम (3.2) लागू होता है यदि घोषणा अलग-अलग 012 में दिखाई देती हैअनुवाद इकाइयां ...

मैं इसे लागू करने के लिए व्याख्या नहीं करता क्योंकि एक ही नाम के साथ सी और सी ++ फ़ंक्शन वास्तव में एक ही कार्य नहीं हैं लेकिन यह व्याख्या गलत हो सकती है।

तो सी ++ 03 7.5/6 से:

एक विशेष नाम सी भाषा लिंकेज हो सकता है के साथ सबसे अधिक एक समारोह में

...

यह तो संकेत मिलता है कि आप हो सकता है अन्य, गैर-सी-लिंकेज, एक ही नाम के साथ कार्य करता है। इस मामले में, सी ++ अधिभार।

+0

बहुत बहुत धन्यवाद, मुझे अभी भी यह भ्रमित करने वाला लगता है कि मुझे लगता है कि मैं इसके खिलाफ अनुशंसा करूंगा। – harald

+0

7.5/5 में मैं आपकी व्याख्या से सहमत हूं: "एक ही कार्य की दो घोषणाएं" एक ही कार्य * को संदर्भित करती हैं, एक ही नाम के साथ अलग-अलग फ़ंक्शंस नहीं। तो 'बाहरी "सी" शून्य फू(); शून्य फू(); 'यूबी है, लेकिन 'बाहरी" सी "शून्य बार(); शून्य बार (int); 'नहीं है। –

2

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

अन्यथा, मुझे कोई महत्वपूर्ण नुकसान नहीं दिख रहा है। यहां तक ​​कि प्रतिलिपि पैरामीटर और रिटर्न वैल्यू के संभावित नुकसान को संकलक- और कार्यान्वयन-विनिर्देशों द्वारा कम किया जा सकता है जो आपको फ़ंक्शन को इनलाइन करने की अनुमति देता है - यदि यह समस्या होने का दृढ़ संकल्प है।

namespace your_project { // You do use one, right? :) 
    void f(int x); 
    void f(char x); 
    void f(other_overloads x); 
} 

extern "C" 
void f(int x) { 
    your_project::f(x); 
} 
+0

दिलचस्प समाधान, अगर मुझे यह अधिकार मिलता है तो आप नामस्थान में सभी ओवरलोड को लेकर पूरी समस्या से बचें। और सी-लिंकेज के साथ एक अलग गैर-नामित समारोह। सुनिश्चित नहीं है कि हम आसानी से ऐसा कर सकते हैं कि हमारी परियोजना में सी ++ कोड विरासत है और किसी अन्य प्रोजेक्ट से निकलता है। इच्छा है कि मैं सभी उत्तरों को स्वीकार कर सकता हूं, वास्तव में ... – harald

+0

@harald: आम तौर पर एक परियोजना से सभी कार्यों, भले ही इसे लाइब्रेरी के रूप में कहीं और इस्तेमाल करने का इरादा नहीं है, पहले से ही नामस्थान में होना चाहिए। –

1

(यह उत्तर सी ++ 14 पर लागू होता है; अन्य उत्तर अब तक सी ++ 03 हैं)।

इसे ओवरलोडिंग का उपयोग करने की अनुमति है। अगर वहाँ कुछ विशेष नाम का एक extern "C" समारोह परिभाषा तो है निम्न स्थितियों में (कोष्ठक में सी ++ 14 के लिए संदर्भ) लागू होते हैं:

  • extern "C" समारोह की घोषणा किसी भी घोषणा या परिभाषा के बिंदु पर दिखाई देना चाहिए उस फ़ंक्शन नाम के ओवरलोड (7.5/5)
  • कोई अन्य नाम extern "C" किसी भी नाम के साथ किसी फ़ंक्शन या वैरिएबल की परिभाषा नहीं होनी चाहिए। (7.5/6)
  • वैश्विक नाम पर एक ही नाम के साथ एक ओवरलोडेड फ़ंक्शन घोषित नहीं किया जाना चाहिए। (7.5/6)
  • उसी नामस्थान के भीतर extern "C" फ़ंक्शन के रूप में, उसी नाम और पैरामीटर सूची के साथ कोई अन्य फ़ंक्शन घोषणा नहीं होनी चाहिए। (7.5/5)

यदि उपर्युक्त नियमों का उल्लंघन किसी भी अनुवाद इकाई में होता है तो संकलक को इसका निदान करना चाहिए; अन्यथा यह बिना किसी निदान के अनिश्चित व्यवहार है।

तो अपने हेडर फाइल कुछ लग सकता है जैसे:

namespace foo 
{ 
    extern "C" void bar(); 
    void bar(int); 
    void bar(std::string); 
} 

पिछले बुलेट बिंदु का कहना है कि आप लिंकेज पर पूरी तरह ओवरलोड नहीं कर सकते; इस बीमार बनाई है:

namespace foo 
{ 
    extern "C" void bar(); 
    void bar();    // error 
} 

आप अलग अलग नामस्थान ऐसा कर सकते हैं हालांकि:

जिस स्थिति में
extern "C" void bar(); 
namespace foo 
{ 
    void bar(); 
} 

, कुछ कोड में एक कॉल bar()::bar पाता है कि क्या अयोग्य देखने के सामान्य नियमों का निर्धारण, foo::bar , या संदिग्ध

+0

अद्यतन के लिए धन्यवाद! – harald

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