2010-01-08 17 views
10

मैंने एसओ पर बाहरी/आंतरिक संबंधों पर मौजूदा प्रश्नों को पढ़ा है। मेरा प्रश्न अलग है - क्या होता है यदि मेरे पास C और C++ के अंतर्गत विभिन्न अनुवाद इकाइयों में बाहरी लिंकेज के साथ एक ही चर के एकाधिक परिभाषाएं हैं?सी और सी ++ के बीच संबंध में अंतर?

उदाहरण के लिए:

/*file1.c*/ 

typedef struct foo { 
    int a; 
    int b; 
    int c; 
} foo; 

foo xyz; 


/*file2.c*/ 

typedef struct abc { 
    double x; 
} foo; 

foo xyz; 

देव-सी ++ का उपयोग करते हुए और एक सी कार्यक्रम के रूप में, उपरोक्त कार्यक्रम को संकलित करता है और लिंक पूरी तरह से; जबकि यह एक सीडी ++ प्रोग्राम के रूप में संकलित किया गया है, तो यह एक बहु redininition त्रुटि देता है। इसे सी के तहत क्यों काम करना चाहिए और सी ++ के साथ क्या अंतर है? क्या यह व्यवहार अपरिभाषित और संकलक-निर्भर है? यह कोड कितना "बुरा" है और अगर मैं इसे दोबारा बनाना चाहता हूं तो मुझे क्या करना चाहिए (मैं इस तरह लिखे गए पुराने कोड में आया हूं)?

उत्तर

4

सी और सी ++ दोनों में "एक परिभाषा नियम" है जो कि प्रत्येक ऑब्जेक्ट को किसी भी प्रोग्राम में केवल एक बार परिभाषित किया जा सकता है। इस नियम के उल्लंघन अपरिभाषित व्यवहार का अर्थ है जिसका अर्थ है कि संकलन करते समय आप नैदानिक ​​संदेश देख सकते हैं या नहीं देख सकते हैं।

फ़ाइल दायरे में निम्नलिखित घोषणाओं के बीच एक भाषा अंतर है, लेकिन यह आपके उदाहरण के साथ समस्या से सीधे चिंता नहीं करता है।

int a; 

सी में यह एक संक्षिप्त परिभाषा है। यह एक ही परिभाषा बनाने के लिए एक ही अनुवाद इकाई में अन्य टेटेटिव परिभाषाओं के साथ मिलकर हो सकता है। सी ++ में यह हमेशा एक परिभाषा है (आपको इसे परिभाषित किए बिना ऑब्जेक्ट घोषित करने के लिए extern का उपयोग करना होगा) और उसी अनुवाद इकाई में उसी ऑब्जेक्ट की किसी भी बाद की परिभाषा एक त्रुटि है।

आपके उदाहरण में दोनों अनुवाद इकाइयों में उनकी टिकाऊ परिभाषाओं से xyz की एक (विरोधाभासी) परिभाषा है।

0

सी प्रोग्राम इस परमिट करता है और स्मृति को एक संघ की तरह थोड़ा व्यवहार करता है। यह दौड़ जाएगा, लेकिन आपको जो भी उम्मीद है वह आपको नहीं दे सकता है।

सी ++ प्रोग्राम (जो मजबूत टाइप किया गया है) सही ढंग से समस्या का पता लगाता है और आपको इसे ठीक करने के लिए कहता है। यदि आप वास्तव में एक संघ चाहते हैं, तो इसे एक के रूप में घोषित करें। यदि आप दो अलग-अलग वस्तुओं को चाहते हैं, तो उनके दायरे को सीमित करें।

+1

सी व्यवहार आपके कार्यान्वयन पर सच हो सकता है लेकिन इसकी भाषा द्वारा गारंटी नहीं है। –

+0

एक चर नाम एक स्मृति पता के लिए सिर्फ एक लेबल है। यदि आप उस लेबल को समझने के लिए दो परिभाषाएं प्रदान करते हैं, तो यह जादू को दो अलग-अलग ऑब्जेक्ट्स का तर्क नहीं देता है। क्या आपने कभी एक लिंकर देखा है जो उस पर अलग व्यवहार करेगा? –

+0

मैं इनकार नहीं करता कि यह सामान्य लिंकर व्यवहार है, यह व्यवहार अन्य भाषाओं और कई सी कार्यान्वयनों द्वारा उपयोग किया जाता है। हालांकि, आपके उत्तर से निहितार्थ यह था कि यह एक अच्छी तरह से परिभाषित व्यवहार है। सी मानक अनुलग्नक जे के मुताबिक, एक कार्यक्रम में एक से अधिक बाहरी परिभाषाओं को एक आम विस्तार देना है, लेकिन इस विस्तार के साथ भी यदि परिभाषाएं सहमत नहीं हैं तो यह अपरिभाषित व्यवहार में परिणाम देती है। –

1

सी ++ प्रतीक को एक से अधिक बार परिभाषित करने की अनुमति नहीं देता है। निश्चित नहीं है कि सी लिंकर क्या कर रहा है, एक अच्छा अनुमान यह हो सकता है कि यह दोनों परिभाषाओं को उसी प्रतीक पर मानचित्रित करता है, जो निश्चित रूप से गंभीर त्रुटियों का कारण बनता है।

पोर्टिंग के लिए मैं व्यक्तिगत सी-फाइलों की सामग्री को अज्ञात नेमस्पेस में रखने की कोशिश करता हूं, जो अनिवार्य रूप से प्रतीकों को अलग करता है, और फ़ाइल को स्थानीय बनाता है, इसलिए वे कहीं और उसी नाम से संघर्ष नहीं करते हैं।

+0

निश्चित रूप से इसे एक से अधिक बार परिभाषित किया जा सकता है। परिभाषाओं को समान होना चाहिए, यद्यपि। – Potatoswatter

+1

@Potatoswatter: ऑब्जेक्ट्स केवल एक बार _defined_ होना चाहिए, वे _declared_ कई बार हो सकते हैं। 'इनलाइन' फ़ंक्शंस विशेष हैं कि उन्हें प्रति अनुवाद इकाई में एक बार परिभाषित किया जा सकता है लेकिन अन्य कार्यों को प्रत्येक प्रोग्राम में केवल एक बार परिभाषित किया जाना चाहिए। –

+0

क्षमा करें, मेरा बुरा: पी – Potatoswatter

2

यह सी ++ के नाम मैंगलिंग के कारण होता है। Wikipedia से:

पहले सी ++ compilers सी स्रोत कोड है, जो तब एक सी संकलक कोड आपत्ति उठाने द्वारा संकलित किया जाएगा करने के लिए अनुवादकों के रूप में लागू किए गए थे; क्योंकि इनमें से, प्रतीक नामों को को सी पहचानकर्ता नियमों के अनुरूप करना था। बाद में, संकलक के उद्भव के साथ उत्पादित मशीन कोड या असेंबली सीधे, सिस्टम के लिंकर आम तौर पर सी ++ प्रतीकों, का समर्थन नहीं करते थे और मैंगलिंग अभी भी आवश्यक था।

के साथ संबंध है compatibility रहे हैं:

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

से http://www.cs.indiana.edu/~welu/notes/node36.html निम्न उदाहरण दिया जाता है:


के लिए

उदाहरण के लिए सी कोड के नीचे

int foo(double*); 
double bar(int, double*); 

int foo (double* d) 
{ 
    return 1; 
} 

double bar (int i, double* d) 
{ 
    return 0.9; 
} 

इसका प्रतीक तालिका होगा (dump -t द्वारा)

[4] 0x18  44  2  1 0 0x2 bar 
[5] 0x0   24  2  1 0 0x2 foo 

एक ही फाइल के लिए, यदि संकलन में g ++, तो प्रतीक तालिका

[4] 0x0   24  2  1 0 0x2 _Z3fooPd 
[5] 0x18  44  2  1 0 0x2 _Z3bariPd 

_Z3bariPd होगा एक समारोह जिसका नाम बार भी है और जिनकी पहली आर्ग पूर्णांक है और दोगुना करने के लिए सूचक है दूसरा तर्क का मतलब है।


0

आपको One Definition Rule मिला है। स्पष्ट रूप से आपके प्रोग्राम में एक बग है, क्योंकि

  • प्रोग्राम कनेक्ट होने के बाद केवल foo नामक एक ऑब्जेक्ट हो सकता है।
  • यदि कुछ स्रोत फ़ाइल में सभी शीर्षलेख फ़ाइलें शामिल हैं, तो इसमें foo की दो परिभाषाएं दिखाई देगी।

सी ++ कंपाइलर्स "नाम मैंगलिंग" के कारण लगभग # 1 प्राप्त कर सकते हैं: लिंक किए गए प्रोग्राम में आपके चर का नाम आपके द्वारा चुने गए से अलग हो सकता है। इस मामले में, यह आवश्यक नहीं है, लेकिन शायद यह है कि आपके कंपाइलर को समस्या का पता चला। # 2, हालांकि, बनी हुई है, इसलिए आप ऐसा नहीं कर सकते हैं।

तुम सच में सुरक्षा तंत्र को हराने के लिए चाहते हैं, तो आप इस तरह mangling कर सकते हैं अक्षम:

extern "C" struct abc foo; 

... अन्य फ़ाइल ...

extern "C" struct foo foo; 

extern "C" लिंकर सी ABI सम्मेलनों का उपयोग करने के निर्देश देता है।

+0

ओह, ज़ाहिर है, जैसा कि किसी और ने बताया है, आपको इसके बजाय 'संघ' का उपयोग करना चाहिए। – Potatoswatter

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