2008-09-15 4 views
117

क्यों हम उपयोग करने की आवश्यकता है:हमें C++ में बाहरी "सी" {# शामिल <foo.h>} क्यों चाहिए?

extern "C" { 
#include <foo.h> 
} 

विशेष रूप से:

  • हम इसे जब इस्तेमाल करना चाहिए?

  • कंपाइलर/लिंकर स्तर पर क्या हो रहा है जिसके लिए हमें इसका उपयोग करने की आवश्यकता है?

  • संकलन/लिंकिंग के मामले में यह उन समस्याओं को हल करता है जिनके लिए हमें इसका उपयोग करने की आवश्यकता होती है?

+0

मैं उलझन में आप अपने प्रश्न शीर्षक में क्या मतलब है हूँ ... आप विस्तार से बता सकते हैं? –

+29

मुझे यकीन नहीं है कि इसे और कैसे रखा जाए। क्या आपने शीर्षक से परे पढ़ा था? – Landon

उत्तर

106

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

(वास्तव में बुनियादी तथ्य, सी ++ के ABI आम तौर पर 'mangles' उनके कार्यों/तरीकों के नाम है, तो एक सी समारोह के रूप में प्रोटोटाइप पर चिह्नित करने के बिना printf() बुला में पाने के लिए, सी ++ वास्तव में, _Zprintf बुला कोड उत्पन्न होगा प्लस अंत में अतिरिक्त बकवास।)

तो: एसी हेडर समेत extern "C" {...}; का उपयोग करें-यह इतना आसान है। अन्यथा, आपके पास संकलित कोड में एक मेल नहीं होगा, और लिंकर चकित होगा। अधिकांश शीर्षकों के लिए, आपको extern की भी आवश्यकता नहीं होगी क्योंकि अधिकांश सिस्टम सी हेडर पहले से ही इस तथ्य के लिए खाते हैं कि उन्हें C++ कोड और पहले से ही extern उनके कोड शामिल किया जा सकता है।

+1

आप और अधिक पर ** विस्तृत कृपया सकते हैं "तथ्य यह है कि वे सी ++ कोड से शामिल किया जा सकता है और पहले से ही अपने कोड extern के लिए सबसे प्रणाली सी हेडर खाते से पहले ही होगा।" **? –

+3

@ बुलेटम। उनमें कुछ ऐसा शामिल है: '#ifdef __cplusplus बाहरी" सी "{ # endif' तो जब सी ++ फ़ाइल से शामिल किया गया तो उन्हें अभी भी सी हेडर के रूप में माना जाता है। – Calmarius

+1

नहीं ';' अंत में जरूरी है। मैं इसे बदल सकते हैं नहीं है, यह कम से कम 6 वर्ण की आवश्यकता है के बाद से क्रम में परिवर्तित करने के लिए एक परिवर्तन लागू करने के लिए -, - बेवकूफ – danger89

13

इसे अलग-अलग कंपाइलर्स नाम-मैंगलिंग करने के तरीके से करना है। एक सी ++ कंपाइलर एक सी कंपाइलर की तुलना में पूरी तरह से अलग तरीके से हेडर फ़ाइल से निर्यात किए गए प्रतीक के नाम को जोड़ देगा, इसलिए जब आप लिंक करने का प्रयास करेंगे, तो आपको एक लिंकर त्रुटि मिलेगी जिसमें कहा गया था कि गायब प्रतीक थे।

इसे हल करने के लिए, हम सी ++ कंपाइलर को "सी" मोड में चलाने के लिए कहते हैं, इसलिए यह सी कंपाइलर के समान तरीके से नाम मैंगलिंग करता है। ऐसा करने के बाद, लिंकर त्रुटियों को ठीक किया गया है।

5

यह नाम उलझन के मुद्दों को हल करने के लिए उपयोग किया जाता है। बाहरी सी का मतलब है कि कार्य "फ्लैट" सी-शैली एपीआई में हैं।

6

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

18

सी ++ में, आपके पास एक नाम साझा करने वाली विभिन्न संस्थाएं हो सकती हैं।उदाहरण के लिए यहाँ कार्यों की एक सूची सभी नामित foo है:

  • A::foo()
  • B::foo()
  • C::foo(int)
  • C::foo(std::string)

आदेश में उन सब को, सी ++ संकलक के बीच अंतर करने नाम-मैंगलिंग या सजावट नामक प्रक्रिया में प्रत्येक के लिए अद्वितीय नाम बनाएंगे। सी कंपाइलर ऐसा नहीं करते हैं। इसके अलावा, प्रत्येक सी ++ संकलक ऐसा कर सकता है यह एक अलग तरीका है।

बाहरी "सी" सी ++ संकलक को बताता है कि ब्रेसिज़ के भीतर कोड पर कोई नाम-मैंगलिंग नहीं करना है। यह आपको सी ++ के भीतर से सी कार्यों को कॉल करने की अनुमति देता है।

10

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

सी में नियम बहुत सरल है, प्रतीक सभी एक ही नाम स्थान में हैं। तो पूर्णांक "मोजे" को "मोजे" के रूप में संग्रहीत किया जाता है और फ़ंक्शन count_socks को "count_socks" के रूप में संग्रहीत किया जाता है।

लिंकर्स सी और अन्य भाषाओं जैसे सी के लिए इस सरल प्रतीक नामकरण नियम के साथ बनाया गया था। तो लिंकर में प्रतीक सिर्फ सरल तार हैं।

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

सी पुस्तकालयों या कोड से सी ++ कोड को जोड़ने के दौरान, आपको सी में लिखे गए बाहरी "सी" की आवश्यकता होती है, जैसे सी पुस्तकालयों के लिए हेडर फाइलें, अपने सी ++ कंपाइलर को बताने के लिए कि इन प्रतीक नामों को उलझाना नहीं है, जबकि आपके शेष सी ++ कोड को निश्चित रूप से उलझाया जाना चाहिए या यह काम नहीं करेगा।

10

हमें इसका उपयोग कब करना चाहिए?

आप सी में सी libaries लिंक कर रहे हैं जब ++ फ़ाइलों

आपत्ति क्या संकलक/लिंकर स्तर हमें की आवश्यकता है कि इसका इस्तेमाल करने पर हो रहा है?

सी और सी ++ प्रतीक नामकरण के लिए विभिन्न योजनाओं का उपयोग करते हैं। यह लिंकर को दी गई लाइब्रेरी में लिंक करते समय सी की योजना का उपयोग करने के लिए कहता है।

कैसे संकलन के मामले में/जोड़ने इस समस्याओं जो इसका इस्तेमाल करने के लिए हमें की आवश्यकता को हल करता है?

सी नामकरण योजना का उपयोग करने से आप सी-शैली प्रतीकों का संदर्भ दे सकते हैं।अन्यथा लिंकर सी ++ - स्टाइल प्रतीकों का प्रयास करेगा जो काम नहीं करेगा।

5

extern "C" {} निर्माण के नाम ब्रेसिज़ के भीतर घोषित पर mangling प्रदर्शन करने के लिए नहीं संकलक निर्देश देता है। आम तौर पर, सी ++ कंपाइलर फ़ंक्शन नामों को "बढ़ाता है" ताकि वे तर्क और वापसी मूल्य के बारे में प्रकार की जानकारी को एन्कोड कर सकें; इसे उलटा नाम कहा जाता है। extern "C" निर्माण मैंगलिंग को रोकता है।

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

104

extern "सी" कैसे उत्पन्न वस्तु फ़ाइल में प्रतीकों नाम दिया जाना चाहिए निर्धारित करता है। यदि कोई फ़ंक्शन बाहरी "सी" के बिना घोषित किया गया है, तो ऑब्जेक्ट फ़ाइल में प्रतीक नाम C++ नाम मैंगलिंग का उपयोग करेगा। यहां एक उदाहरण दिया गया है। इसलिए जैसे

को देखते हुए test.c:

void foo() { } 

संकलन और वस्तु फ़ाइल में प्रतीकों लिस्टिंग देता है:

$ g++ -c test.C 
$ nm test.o 
0000000000000000 T _Z3foov 
       U __gxx_personality_v0 

foo समारोह वास्तव में "_Z3foov" कहा जाता है। इस स्ट्रिंग में अन्य चीजों के साथ रिटर्न प्रकार और पैरामीटर के लिए प्रकार की जानकारी होती है। आप के बजाय इस तरह test.c लिखते हैं:

extern "C" { 
    void foo() { } 
} 

फिर संकलन और प्रतीकों को देखो:

$ g++ -c test.C 
$ nm test.o 
       U __gxx_personality_v0 
0000000000000000 T foo 

आप सी लिंकेज मिलता है। ऑब्जेक्ट फ़ाइल में "foo" फ़ंक्शन का नाम केवल "foo" है, और इसमें सभी फैंसी प्रकार की जानकारी नहीं है जो नाम मैंगलिंग से आता है।

आप आम तौर पर निर्वासन 'सी' के भीतर एक शीर्ष लेख शामिल {} यदि कोड है कि यह साथ चला जाता है एक सी संकलक के साथ संकलित किया गया था, लेकिन आप C++ से यह कॉल करने के लिए कोशिश कर रहे हैं। जब आप ऐसा करते हैं, तो आप संकलक को बता रहे हैं कि शीर्षलेख में सभी घोषणाएं सी लिंकेज का उपयोग करेंगी। जब आप अपने कोड लिंक करें, अपने ओ फ़ाइलें संदर्भ "foo" नहीं "_Z3fooblah" है, जो उम्मीद है कि मेल खाता है जो पुस्तकालय आप के खिलाफ लिंक कर रहे हैं में है शामिल होंगे।

अधिकांश आधुनिक पुस्तकालयों ऐसे हेडर के आसपास गार्ड डाल इतना है कि प्रतीकों सही लिंकेज के साथ घोषित कर रहे हैं। जैसे मानक हेडर का एक बहुत में आप मिल जाएगा:

#ifdef __cplusplus 
extern "C" { 
#endif 

... declarations ... 

#ifdef __cplusplus 
} 
#endif 

यह सुनिश्चित करती है कि सी ++ कोड शीर्ष, क्या सी पुस्तकालय में है अपने वस्तु फ़ाइल मैच में प्रतीकों में शामिल है। यदि आपको पुराना है तो आपको केवल अपने सी हेडर के आस-पास बाहरी "सी" {} रखना होगा और इन गार्डों में पहले से ही नहीं है।

+2

कुछ संक्षिप्त उदाहरण वास्तव में अच्छी बातें कर रहे हैं! – zhy

6

आपको किसी भी समय बाहरी "सी" का उपयोग करना चाहिए जिसमें आप एक सी ++ फ़ाइल में उपयोग किए गए एक फ़ाइल कंपाइलर द्वारा संकलित फ़ाइल में रहने वाले हेडर परिभाषित फ़ंक्शंस को शामिल करते हैं। (कई मानक सी पुस्तकालयों में डेवलपर के लिए इसे आसान बनाने के लिए अपने हेडर में यह चेक शामिल हो सकता है)

उदाहरण के लिए, यदि आपके पास 3 फाइलें, util.c, util.h, और main.cpp दोनों के साथ कोई प्रोजेक्ट है .c और .cpp फ़ाइलों को C++ कंपाइलर (g ++, cc, आदि) के साथ संकलित किया गया है, तो इसकी वास्तव में आवश्यकता नहीं है, और यहां तक ​​कि लिंकर त्रुटियों का कारण भी हो सकता है। यदि आपकी बिल्ड प्रक्रिया ut.c के लिए एक नियमित सी कंपाइलर का उपयोग करती है, तो आपको ut.h सहित बाहरी "सी" का उपयोग करने की आवश्यकता होगी।

क्या हो रहा है यह है कि सी ++ फ़ंक्शन के पैरामीटर को इसके नाम पर एन्कोड करता है। इस तरह कार्य ओवरलोडिंग काम करता है।जो कुछ सी फ़ंक्शन के साथ होता है वह नाम की शुरुआत में अंडरस्कोर ("_") का जोड़ होता है। निर्वासन 'सी' का उपयोग किए बिना लिंकर DoSomething @@ पूर्णांक @ नाव() जब समारोह के वास्तविक नाम _DoSomething है() या सिर्फ DoSomething() नाम की एक समारोह के लिए खोज कर रहे होंगे।

extern "सी" का उपयोग करते हुए सी ++ संकलक है कि यह एक समारोह है कि सी ++ एक के बजाय सी नामकरण परंपरा इस प्रकार के लिए दिखना चाहिए बताकर ऊपर समस्या का हल।

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