2010-01-20 9 views
9

मैं अगर #defined रक्षा की और शीर्ष पर एक बार एक #pragma है एक चरित्र सरणी एक हैडरहैडर गार्ड्स और LNK4006

//header.h 
const char* temp[] = {"JeffSter"}; 

हेडर में निर्धारित किया है। यदि यह हेडर एकाधिक स्थानों में शामिल है, तो मुझे एक एलएनके 40000 - चार const * * temp पहले से ही blahblah.obj में परिभाषित किया गया है। तो, मेरे पास इस

  1. के बारे में कुछ प्रश्न हैं यदि मेरे पास गार्ड हैं तो ऐसा क्यों होता है? मैंने सोचा कि उन्होंने पहली पहुंच के बाद हेडर को पढ़ने से रोका था।
  2. इस हेडर में कई enums क्यों LNK4006 चेतावनियां नहीं देते हैं?
  3. यदि मैं हस्ताक्षर से पहले स्थैतिक जोड़ता हूं, तो मुझे चेतावनी नहीं मिलती है। इस तरह से करने के प्रभाव क्या हैं।
  4. क्या ऐसा करने का कोई बेहतर तरीका है जो त्रुटि से बचाता है, लेकिन मुझे हेडर में सरणी घोषित करने देता है। मैं वास्तव में एक सरणी परिभाषा के लिए एक सीपीपी फ़ाइल होने से नफरत करता हूं।

उत्तर

12

इस अगर मैं जगह में गार्ड है क्यों होता है? मैंने सोचा कि उन्होंने पहली पहुंच के बाद हेडर को पढ़ने से रोका था।

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

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

तो, जैसा कि आपने पाया है, ऊपर दिए गए कारण के लिए हेडर फ़ाइल में वेरिएबल्स को परिभाषित करना एक बुरा विचार है।

इस शीर्षलेख में कई enums क्यों LNK4006 चेतावनियां नहीं देते हैं?

क्योंकि, वे "वैश्विक चर" को परिभाषित नहीं करते हैं, वे केवल प्रकारों के बारे में घोषणाएं हैं, आदि। वे किसी भी भंडारण को आरक्षित नहीं करते हैं।

यदि मैं हस्ताक्षर से पहले स्थैतिक जोड़ता हूं, तो मुझे चेतावनी नहीं मिलती है। इस तरह से करने के प्रभाव क्या हैं।

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

static int i; 

अपने शीर्षक में, प्रत्येक स्रोत फ़ाइल जिसमें आप शीर्ष लेख एक अलगint चर i, जो स्रोत फ़ाइल के अदृश्य बाहर है मिल जाएगा शामिल हैं। इसे आंतरिक लिंक के रूप में जाना जाता है।

क्या ऐसा करने का कोई बेहतर तरीका है जो त्रुटि से बचाता है, लेकिन मुझे हेडर में सरणी घोषित करने देता है। मैं वास्तव में एक सरणी परिभाषा के लिए एक सीपीपी फ़ाइल होने से नफरत करता हूं।

आप सरणी चाहते हैं अपने सभी सी ++ फ़ाइलों से एक वस्तु दिखाई दे सकता है, आपको क्या करना चाहिए:

extern int array[SIZE]; 

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

int array[SIZE]; 

आप शीर्ष लेख में एक अंतर के कारण गलतियों को पकड़ने के लिए अनुमति देने के लिए, साथ ही ऊपर स्रोत फ़ाइल में हेडर होना चाहिए और स्रोत फ़ाइल।

असल में, extern संकलक कि कहता है "array कहीं परिभाषित किया गया है, और प्रकार int, और आकार SIZE है।" फिर, आप वास्तव में array को केवल एक बार परिभाषित करते हैं। लिंक चरण पर, सबकुछ अच्छी तरह से हल हो जाता है।

4

गार्ड शामिल करें आपको एक ही शीर्षलेख को उसी फ़ाइल में बार-बार शामिल करने से बचाता है - लेकिन इसे अलग-अलग फ़ाइलों में शामिल करने से नहीं।
क्या होता है कि लिंकर एक से अधिक वस्तु फ़ाइल में temp देखता है - आप हल कर सकते हैं temp स्थिर बनाने या यह एक अनाम नेम स्पेस में रखकर कि:

static const char* temp1[] = {"JeffSter"}; 
// or 
namespace { 
    const char* temp2[] = {"JeffSter"}; 
} 

वैकल्पिक रूप से आप एक स्रोत फ़ाइल जो temp को परिभाषित करता है का उपयोग कर सकते और सिर्फ शीर्षक में निर्वासन के रूप में यह घोषणा करते हैं:

// temp.cpp: 
const char* temp[] = {"JeffSter"}; 

// header.h: 
extern const char* temp[]; 
-1

हैंग पर ... आप अपने घोषणाओं अप मिश्रण कर रहे हैं ... आप क्या कहा अपने हेडर फाइल में 'चार स्थिरांक * * अस्थायी' अभी तक आप 'स्थिरांक चार * temp [] = {"जेफटर"}; '।

देखें अनुभाग C FAQ का 6.1, के तहत 'धारा 6. Arrays और प्वाइंटर', उद्धृत करने के लिए:

 
6.1: I had the definition char a[6] in one source file, and in 
    another I declared extern char *a. Why didn't it work? 

A: In one source file you defined an array of characters and in the 
    other you declared a pointer to characters. The declaration 
    extern char *a simply does not match the actual definition. 
    The type pointer-to-type-T is not the same as array-of-type-T. 
    Use extern char a[]. 

    References: ISO Sec. 6.5.4.2; CT&P Sec. 3.3 pp. 33-4, Sec. 4.5 
    pp. 64-5. 

समस्या का स्रोत है। अपनी घोषणा और परिभाषाओं का मिलान करें। क्षमा करें अगर यह धुंधला लगता है, लेकिन मैं यह देखने में मदद नहीं कर सका कि लिंकर आपको क्या बता रहा था ...

उम्मीद है कि यह मदद करता है, सर्वश्रेष्ठ संबंध, टॉम।

+1

लिंकर सिर्फ सूचक वाक्यविन्यास में सरणी वाक्यविन्यास का अनुवाद कर रहा है। यह कोई त्रुटि नहीं है, यह सिर्फ एक चेतावनी है, कार्यक्रम अपेक्षित के रूप में निष्पादित करता है। – Steve

4
  1. हैडर गार्ड पूरी तरह से कुछ भी नहीं आपके पूरे कार्यक्रम में कई परिभाषाएं को रोकने के साथ क्या करना है। हेडर गार्ड का उद्देश्य समान अनुवाद इकाई (.cpp फ़ाइल) में एक ही शीर्षलेख फ़ाइल के एकाधिक समावेशन को रोकने के लिए है। दूसरे शब्दों में, वे में एक ही स्रोत फ़ाइल में कई परिभाषाओं को रोकने के लिए मौजूद हैं। और वे आपके मामले में इरादे के अनुसार काम करते हैं।

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

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

  3. static जोड़कर आप अपना ऑब्जेक्ट आंतरिक लिंक देते हैं। इससे त्रुटि गायब हो जाएगी, क्योंकि अब यह ओडीआर बिंदु से बिल्कुल ठीक है। लेकिन यह प्रत्येक अनुवाद इकाई में एक स्वतंत्र temp ऑब्जेक्ट को परिभाषित करेगा जिसमें आपकी हेडर फ़ाइल शामिल है। एक ही प्रभाव आप भी सी में const वस्तुओं ++ डिफ़ॉल्ट रूप से आंतरिक संबंध है के बाद से

    const char* const temp[] = { "JeffSter" }; 
    

    कर सकता है प्राप्त करने के लिए।

  4. यह इस बात पर निर्भर करता है कि आपको बाहरी लिंक (यानी पूरे कार्यक्रम के लिए एक) या आंतरिक लिंकेज (प्रत्येक अनुवाद इकाई के लिए अद्वितीय) के साथ एक वस्तु की आवश्यकता है या नहीं। यदि आपको बाद वाले की आवश्यकता है, तो ऊपर दिखाए गए अनुसार static और/या अतिरिक्त const (यदि यह आपके लिए काम करता है) का उपयोग करें।

    आप पूर्व (बाह्य संबंध) की जरूरत है, तो आप हेडर फाइल

    extern const char* temp[]; 
    

    में एक गैर को परिभाषित घोषणा रख दिया और एक में परिभाषा के लिए कदम और केवल एक ही .cpp फ़ाइल चाहिए

    char* const temp[] = { "JeffSter" }; 
    

    शीर्षलेख फ़ाइल में उपर्युक्त घोषणा अधिकांश उद्देश्यों के लिए काम करेगी। हालांकि, यह अज्ञात आकार की एक सरणी के रूप में temp घोषित करता है - एक अधूरा प्रकार। आप ज्ञात आकार की एक सरणी के रूप में यह घोषणा करने के लिए चाहते हैं, आप आकार मैन्युअल

    extern const char* temp[1]; 
    

    निर्दिष्ट करें और इन-सिंक घोषणा और परिभाषा के बीच इसे रखने के लिए याद करने के लिए किया है।

0

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

मैं इस पृष्ठ पर एलएनके 40000 चेतावनी के कारण पूछताछ के परिणामस्वरूप उतरा, एक लंबे समय से स्थापित सरणी को बुलाकर, जिसे मैंने अभी अनुवाद इकाई से स्थानांतरित किया है जो मेरे डीएलएलमेन नियमित को निजी हेडर में परिभाषित करता है जो अधिकांश में शामिल है अनुवाद पुस्तकालयों में से इस पुस्तकालय शामिल है। मैंने पिछले 11 वर्षों में इस लाइब्रेरी को सैकड़ों बार संकलित किया है, और मैंने कभी यह चेतावनी नहीं देखी थी।

इस पृष्ठ को पढ़ने के कुछ ही समय बाद, मैंने त्रुटि का कारण खोजा, यह था कि परिभाषा गार्ड ब्लॉक के बाहर थी जो मॉड्यूल में परिभाषित सभी चीजों की रक्षा करता है जो डीएलएलमेन को भी परिभाषित करता है, जहां मैं आमतौर पर इकट्ठा होता हूं सभी मेमोरी ब्लॉक जिन्हें बाहरी लिंकेज की आवश्यकता होती है। जैसा कि अपेक्षित था, गार्ड ब्लॉक के अंदर टेबल को ले जाने से चेतावनियों को समाप्त कर दिया गया, जिससे मुझे केवल दो के साथ छोड़ दिया गया, जो कि एक नई नई बाहरी रूप से जुड़ी हुई तालिका से संबंधित है।

टेकवे: आप हेडर में चर परिभाषित कर सकते हैं, और यह सामान्य ब्लॉक डालने के लिए एक शानदार जगह है, लेकिन अपने गार्ड को ध्यान दें।