2010-05-21 9 views
12

में मैं 2 तरीकों का उपयोग कर घोषित करने और char * परिभाषित करने के लिए लोगों को देखा है करने के लिए एक मूल्य निर्धारित करने के लिए है।यह उचित एक "स्थिरांक चार *" हेडर फाइल

Medhod 1: हेडर फाइल नीचे

extern const char* COUNTRY_NAME_USA = "USA"; 

Medhod 2 है:
हेडर फाइल नीचे घोषणा है:

extern const char* COUNTRY_NAME_USA; 

cpp फ़ाइल नीचे परिभाषा है:

extern const char* COUNTRY_NAME_USA = "USA"; 
  1. विधि 1 गलत तरीके से गलत है?
  2. दोनों के बीच क्या अंतर है?
  3. मैं "const char * const var" के बीच अंतर को समझते हैं, और "const char * var"। यदि उपर्युक्त तरीकों में यदि "const char * const var" हैडर में घोषित और परिभाषित किया गया है, तो विधि 1 में यह समझ में आएगा?

उत्तर

24

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

दूसरी विधि सही है। कीवर्ड extern cpp फ़ाइल में हालांकि परिभाषा वैकल्पिक है, यानी आप सिर्फ हेडर फाइल से घोषणा संभालने

const char* COUNTRY_NAME_USA = "USA" 

क्या कर सकते हैं इस अनुवाद इकाई में इस परिभाषा से पहले आती है।

इसके अलावा, मुझे लगता है कि ऑब्जेक्ट नाम पूंजीकृत होने के बाद से, शायद यह स्थिर होना है। ऐसा इसलिए है, तो इसे const char* const COUNTRY_NAME_USA के रूप में घोषित/परिभाषित किया जाना चाहिए (अतिरिक्त const नोट करें)।

अंत में, खाते में है कि पिछले विस्तार ले रही है, तो आप सिर्फ अपने निरंतर रूप

const char* const COUNTRY_NAME_USA = "USA"; // no `extern`! 
हेडर फाइल में

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

+0

लेकिन क्या होगा अगर मैं नीचे हेडर फाइल सिर्फ एक बार शामिल करने के लिए, मैं अभी भी लिंकर समय त्रुटियों होगा: #ifndef MY_HDR_FILE_H_ #define MY_HDR_FILE_H_ #endif, अगर मैं न मेरी घोषणा – sud

+0

@sud में 2 स्थिरांक है: मैं बात कर रहा हूँ * अलग * अनुवाद इकाइयों में हेडर फ़ाइल को शामिल करने के बारे में। आपके '# ifndef' गार्ड के पास इसके साथ कुछ भी करने के लिए बिल्कुल कुछ नहीं है, यह होने से रोका नहीं जा सकता है और इससे कोई फर्क नहीं पड़ता। आपको पहले संस्करण के साथ एक ही लिंकर त्रुटियां मिलेंगी। – AnT

+0

@ एंड्रे: स्पष्टीकरण के लिए बहुत बहुत धन्यवाद। आपकी टिप्पणी में आपने उल्लेख किया है कि "const char * const COUNTRY_NAME_USA =" यूएसए "है;" एक एचडीआर फ़ाइल में सबसे अच्छा होगा, लेकिन प्रत्येक अनुवाद इकाई को अपना खुद का अंतराल मिलेगा। क्या इसका मतलब यह है कि रनटाइम पर प्रभावशाली मुद्दे होंगे। मेरा मतलब है कि निष्पादन योग्य आकार बड़ा हो क्योंकि प्रत्येक ट्रांसलेशन इकाई की अपनी प्रतिलिपि है? इसके अलावा डीबगिंग के दौरान मैं कोर डंप में चार पॉइंटर का पता देख पाऊंगा। – sud

9

फ़ायदा क्या है?

आप तार (कि स्थानीय किया जा सकता है) देखने के लिए चाहते हैं, यह सबसे अच्छा होगा:

namespace CountryNames { 
    const char* const US = "USA"; 
}; 

के बाद से सूचक स्थिरांक है, यह अब आंतरिक संबंध है और कई परिभाषाएं पैदा नहीं होगी। अधिकतर लिंकर अनावश्यक स्थिरांक को भी जोड़ देंगे, इसलिए आप निष्पादन योग्य में जगह बर्बाद नहीं करेंगे।

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

+0

क्षमा करें मुझे उपरोक्त मेरे सभी कोड में शुरुआत में मेरे प्रश्न में 'बाहरी' जोड़ने से चूक गया। मैं बाहरी जोड़ना चाहता था लेकिन मैं भूल गया। अब जब मैंने बाहरी जोड़ा, तो मुझे किस तरह जाना चाहिए? विधि -1 या विधि -2 – sud

+0

स्पष्टीकरण के लिए बहुत बहुत धन्यवाद। अगर मैं "एचडीआरआर * कॉन्स यूएस =" यूएसए "का उपयोग करता हूं; मेरी एचडीआर फाइल में यदि मेरा लिंकर अनावश्यक स्थिरांक को गठबंधन नहीं करता है, तो रन टाइम पर मैं पॉइंटर 'अमेरिका के पते के साथ कोर डंप का उपयोग करके डीबग कर पाऊंगा ' – sud

+0

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

5

आप वैश्विक चर होना आवश्यक है, तो सामान्य अभ्यास के लिए उन्हें एक ज फ़ाइल में घोषित करने और उन्हें एक (और केवल एक) .cpp फ़ाइल में परिभाषित करने के लिए है।

एक .h फ़ाइल में;

extern int x; 

एक .cpp फ़ाइल में;

int x=3; 

मैं पूर्णांक का इस्तेमाल किया है (सबसे मौलिक बुनियादी प्रकार शायद?) के बजाय स्थिरांक चार * अपने उदाहरण के रूप में आपकी समस्या का सार चर के प्रकार पर निर्भर नहीं करता है क्योंकि।

मूल विचार यह है कि आप एक चर कई बार घोषित कर सकते हैं, इसलिए प्रत्येक .cpp फ़ाइल जिसमें .h फ़ाइल शामिल है वेरिएबल घोषित करती है, और यह ठीक है। लेकिन आप इसे केवल एक बार परिभाषित करते हैं। परिभाषा वह बयान है जहां आप वैरिएबल प्रारंभिक मान असाइन करते हैं, (एक = के साथ)। आप .h फ़ाइलों में परिभाषा नहीं चाहते हैं, क्योंकि तब .h फ़ाइल एकाधिक .cpp फ़ाइलों द्वारा शामिल की जाती है, तो आपको कई परिभाषाएं मिलेंगी। यदि आपके पास एक चर के एकाधिक परिभाषाएं हैं, तो लिंक समय पर एक समस्या है क्योंकि लिंकर चर के पते को असाइन करना चाहता है और यदि इसकी कई प्रतियां हैं तो उचित रूप से ऐसा नहीं कर सकता है।

सूड के भ्रम को आजमाने और आसानी से जोड़ने के लिए अतिरिक्त जानकारी बाद में जोड़ा गया;

इसे बेहतर समझने के लिए अपनी समस्या को कम से कम भागों में कम करने का प्रयास करें;

कल्पना कीजिए कि आपके पास एक प्रोग्राम है जिसमें तीन .cpp फ़ाइलें शामिल हैं। प्रोग्राम बनाने के लिए प्रत्येक .cpp को तीन ऑब्जेक्ट फ़ाइलों को बनाने के लिए अलग से संकलित किया जाता है, फिर तीन ऑब्जेक्ट फ़ाइलें एक साथ जुड़ी होती हैं। यदि तीन .cpp फ़ाइलें निम्नानुसार हैं (उदाहरण ए, अच्छा संगठन);

file1.cpp

extern int x; 

file2.cpp

extern int x; 

file3.cpp

extern int x; 

तब फ़ाइलें संकलन और समस्या के बिना एक साथ लिंक (कम से कम जहाँ तक होगा परिवर्तनीय एक्स चिंतित है)। कोई समस्या नहीं है क्योंकि प्रत्येक फ़ाइल केवल परिवर्तनीय एक्स घोषित कर रही है। एक घोषणा बस यह बता रही है कि वहां कहीं भी एक चर है जो मैं (या नहीं) उपयोग कर सकता हूं।

एक ही चीज़ प्राप्त करने का एक बेहतर तरीका निम्नलिखित है (उदाहरण ए, बेहतर संगठन);

header.h

extern int x; 

file1.cpp

#include "header.h" 

file2.cpp

#include "header.h" 

file3.cpp

#include "header.h" 

यह तीनों संकलनों में से प्रत्येक के लिए प्रभावी रूप से वही है, क्योंकि संकलक पहले से ही उसी पाठ को देखता है क्योंकि यह .cpp फ़ाइल (या अनुवाद इकाई के रूप में अनुवाद इकाई) को संसाधित करता है, क्योंकि # अंतर्निहित निर्देश केवल दूसरे से टेक्स्ट खींचता है फ़ाइल। फिर भी यह पहले के उदाहरण पर एक सुधार है क्योंकि हमारे पास केवल एक फ़ाइल में हमारी घोषणा है, न कि कई फाइलों में।

अब एक और कामकाजी उदाहरण (उदाहरण बी, अच्छा संगठन) पर विचार करें;

file1.cpp

extern int x; 

file2.cpp

extern int x; 

file3.cpp

extern int x; 
int x=3; 

यह ठीक रूप में अच्छी तरह से काम करेगा। सभी तीन .cpp फ़ाइलें x घोषित करती हैं और एक वास्तव में इसे परिभाषित करता है। हम आगे बढ़ सकते हैं और वेरिएबल एक्स में हेरफेर करने वाली तीन फाइलों में से किसी एक में फ़ंक्शंस के भीतर और कोड जोड़ सकते हैं और हमें कोई त्रुटि नहीं मिलेगी। फिर हमें एक हेडर फ़ाइल का उपयोग करना चाहिए ताकि घोषणा केवल एक भौतिक फ़ाइल (उदाहरण बी, बेहतर संगठन) में हो।

header.h

extern int x; 

file1.cpp

#include "header.h" 

file2.cpp

#include "header.h" 

file3.cpp

#include "header.h" 
int x=3; 

अंत में एक उदाहरण पर विचार करें जो सिर्फ काम नहीं करेगा (उदाहरण सी, काम नहीं करता है);

file1.cpp

int x=3; 

file2.cpp

int x=3; 

file3.cpp

int x=3; 

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

अलग-अलग परिभाषाओं को एक तरफ देने के रूप में विभिन्न प्रारंभिक मान समस्या का समाधान नहीं करते हैं। कीवर्ड स्थैतिक के साथ प्रत्येक परिभाषा से पहले समस्या का समाधान होता है क्योंकि अब चर वैश्विक रूप से दिखाई नहीं दे रहे हैं, बल्कि .cpp फ़ाइल में परिभाषित किए गए हैं।

यदि आप एक शीर्षलेख फ़ाइल में वैश्विक चर परिभाषा डालते हैं, कुछ भी आवश्यक नहीं बदला है (उदाहरण सी, हेडर संगठन इस मामले में सहायक नहीं है);

header.h

int x=3; // Don't put this in a .h file, causes multiple definition link error 

file1.cpp

#include "header.h" 

file2.cpp

#include "header.h" 

file3.cpp

#include "header.h" 

पुhew, मुझे उम्मीद है कि कोई इसे पढ़ता है और इससे कुछ लाभ मिलता है। कभी-कभी प्रश्नकर्ता बुनियादी अवधारणाओं के संदर्भ में एक सरल व्याख्या के लिए रो रहा है जो एक उन्नत कंप्यूटर वैज्ञानिक की व्याख्या नहीं है। के बाद से यह एक वस्तु COUNTRY_NAME_USA के परिभाषा साथ हेडर फाइल में बाहरी संबंध बनाता है

+0

लेकिन क्या मैं हेडर फाइल सिर्फ एक बार शामिल करने के लिए नीचे दिए गए हैं, तो मैं अभी भी लिंकर समय त्रुटियों होगा,: #ifndef MY_HDR_FILE_H_ #define MY_HDR_FILE_H_ – sud

+0

#endif शामिल गार्ड एक बार से अधिक पार्स किया जाता से हेडर फाइल को रोकने के * प्रति संकलन इकाई *। अलग .cpp फ़ाइलें अभी भी हेडर फ़ाइल को कई बार संसाधित करती हैं। –

+0

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