2009-07-22 13 views
48

यदि मेरे पास एक चर है जो कई स्रोतों में उपयोग किया जा सकता है - क्या यह एक शीर्षलेख में घोषित करने का एक अच्छा अभ्यास है? या .c फ़ाइल में इसे घोषित करना बेहतर है और अन्य फ़ाइलों में extern का उपयोग करना बेहतर है?शीर्षलेख फ़ाइल में परिवर्तनीय घोषणा

उत्तर

89

आप घोषित करना चाहिए एक हेडर फाइल में चर:

extern int x; 

और तो परिभाषित करें एक सी फ़ाइल:

int x; 

सी में, परिभाषा और घोषणा के बीच का अंतर यह है कि परिभाषा चर के लिए स्थान सुरक्षित रखती है, जबकि घोषणा केवल परिवर्तनीय तालिका में चर को प्रस्तुत करती है (और लिंकर इसे आने पर इसकी तलाश करने का कारण बनती है समय लिंक करने के लिए)।

+3

** दोनों ** घोषणाएं हैं! फ़ाइल-स्कोप पर, दूसरा एक पूर्ण (पूर्ण) परिभाषा नहीं है, लेकिन एक _tentative परिभाषा_ है। – Olaf

29

आप इसे हेडर फ़ाइल में extern के रूप में घोषित कर सकते हैं, और इसे बिल्कुल 1 .c फ़ाइल में परिभाषित कर सकते हैं।

ध्यान दें कि कि ग फ़ाइल भी शीर्ष लेख का उपयोग करना चाहिए और उस मानक पैटर्न की तरह दिखता है:

// file.h 
extern int x; // declaration 

// file.c 
#include "file.h" 
int x = 1; // definition and re-declaration 
+0

वास्तव में यह * हमेशा हेडर का उपयोग करना चाहिए, ताकि अगर घोषणा और परिभाषा के बीच प्रकार निकल जाए तो संकलक आपको बताएगा। – caf

+0

बिल्ली, आप सही हैं, मैं इसे फिर से शब्द दूंगा। –

9

आप की तरह

int x; 
एक हेडर फाइल में

जो तब कई स्थानों में शामिल किया गया है यह घोषणा हैं, तो आप एक्स के कई उदाहरण के साथ खत्म हो जाएगा (और संभवत: संकलन या लिंक समस्याओं)।

इस दृष्टिकोण का सही तरीका हेडर फाइल कहना

extern int x; /* declared in foo.c */ 

और फिर foo.c में आप कह सकते हैं

int x; /* exported in foo.h */ 

तो आप के रूप में कई में अपने हेडर फाइल को शामिल कर सकते है आपको पसंद के स्थान।

3

कुंजी हेडर फ़ाइल में वेरिएबल की घोषणाओं को रखने और स्रोत फ़ाइल को समान रखना है।

मैं इस चाल

------sample.c------ 
#define sample_c 
#include sample.h 

(rest of sample .c) 

------sample.h------ 
#ifdef sample_c 
#define EXTERN 
#else 
#define EXTERN extern 
#endif 

EXTERN int x; 

Sample.c केवल एक बार संकलित किया गया है का उपयोग करें और यह चर को परिभाषित करता है। नमूना.h शामिल करने वाली कोई भी फ़ाइल केवल चर के "बाहरी" को दी जाती है; यह उस चर के लिए स्थान आवंटित करता है।

जब आप एक्स के प्रकार को बदलते हैं, तो यह सभी के लिए बदल जाएगा। आपको इसे स्रोत फ़ाइल और हेडर फ़ाइल में बदलने के लिए याद रखने की आवश्यकता नहीं होगी।

+2

आप प्रारंभिकरण से कैसे निपटते हैं? - बाहरी int x = 6; अधिकांश कंपाइलरों पर चेतावनी देगा। – Dipstick

+0

@ क्रिसशिस - यह एक सीमा है। चर में प्रारंभ करने के लिए मेरे पास आमतौर पर प्रत्येक मॉड्यूल में एक इनिट() होता है। – Robert

+0

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

0

इस समाधान के बारे में क्या?

#ifndef VERSION_H 
#define VERSION_H 

static const char SVER[] = "14.2.1"; 
static const char AVER[] = "1.1.0.0"; 

#else 

extern static const char SVER[]; 
extern static const char AVER[]; 

#endif /*VERSION_H */ 

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

+1

1) #ifndef गार्ड * एकल * स्रोत फ़ाइल में कई परिभाषाओं को रोकता है (इस प्रकार बाहरी परिभाषा कुछ भी नहीं करती है)। 2) एक हेडर में स्थिर चर घोषित करने का अर्थ है कि इसमें शामिल प्रत्येक स्रोत फ़ाइल में एक साझा साझा चर के बजाय उस चर का अपना संस्करण होगा। तकनीकी रूप से यह लिंक होगा, लेकिन व्यवहार वांछित नहीं हो सकता है (इस उदाहरण में कॉन्स वैरिएबल का उपयोग नहीं किया जा सकता है, लेकिन गैर-कॉन्स के लिए इसका उपयोग करें और आप इसे महत्वपूर्ण देखेंगे)। स्वीकृत उत्तर लगभग हमेशा उचित समाधान है। – Assimilater

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