हेडर फ़ाइल में क्या होना चाहिए और क्या नहीं होना चाहिए? [बन्द है]


71

हेडर फ़ाइल में क्या चीजें बिल्कुल शामिल नहीं होनी चाहिए?

अगर उदाहरण के लिए, मैं एक दस्तावेज उद्योग मानक प्रारूप के साथ काम कर रहा हूं जिसमें बहुत सारे स्थिरांक हैं, तो क्या उन्हें हेडर फ़ाइल में परिभाषित करना अच्छा है (यदि मैं उस प्रारूप के लिए एक पार्सर लिख रहा हूं)?

हेडर फ़ाइल में क्या कार्य होने चाहिए?
क्या कार्य नहीं करना चाहिए?


1
लघु और दर्द रहित: परिभाषाएँ और घोषणाएँ जो एक से अधिक मॉड्यूल में आवश्यक हैं।
ott-- 20

21
इस प्रश्न को "बहुत व्यापक" के रूप में चिह्नित करना और बंद करना मॉडरेशन का एक निरपेक्ष शर्मनाक ओवरकिल है। यह प्रश्न वास्तव में पूछता है कि मैं क्या देख रहा हूं - प्रश्न अच्छी तरह से बनता है और एक बहुत स्पष्ट प्रश्न पूछता है: सबसे अच्छे अभ्यास क्या हैं? यदि यह सॉफ़्टवेयर-प्रेषण के लिए "बहुत व्यापक" है .. तो हम इस पूरे फ़ोरम को बंद कर सकते हैं।
ग्यूचर

टी एल; डॉ। C ++ के लिए, Bjarne Stroustrup (इसके निर्माता) द्वारा लिखित "The C ++ प्रोग्रामिंग लैंग्वेज" के चौथे संस्करण में, धारा 15.2.2 में वर्णित है कि हेडर में क्या होना चाहिए और क्या नहीं होना चाहिए। मुझे पता है कि आपने C को प्रश्न टैग किया था, लेकिन कुछ सलाह भी लागू हैं। मुझे लगता है कि यह एक अच्छा सवाल है ...
horro

जवाबों:


57

हेडर में क्या रखा जाए:

  • #includeहेडर को किसी स्रोत फ़ाइल में शामिल करने पर हेडर को संकलित करने के लिए आवश्यक निर्देशों का न्यूनतम सेट ।
  • प्रीप्रोसेसर उन चीजों की परिभाषा देता है जिन्हें साझा करने की आवश्यकता होती है और जो केवल प्रीप्रोसेसर के माध्यम से पूरी हो सकती है। सी में भी, प्रीप्रोसेसर प्रतीकों को न्यूनतम रखा जाता है।
  • संरचना की परिभाषाएं, फ़ंक्शन प्रोटोटाइप, और हेडर के शरीर में वैश्विक चर घोषणाओं को अनिवार्य बनाने के लिए आवश्यक संरचनाओं की अग्रेषण घोषणाएं।
  • डेटा संरचनाओं और गणना की परिभाषाएँ जो कई स्रोत फ़ाइलों के बीच साझा की जाती हैं।
  • फ़ंक्शंस और वैरिएबल के लिए घोषणाएँ जिनकी परिभाषाएँ लिंकर को दिखाई देंगी।
  • इनलाइन फ़ंक्शन परिभाषाएँ, लेकिन यहाँ ध्यान रखें।

हेडर में क्या नहीं है:

  • आभार #includeनिर्देश। उन आभार में उन चीजों को फिर से शामिल करना शामिल है जिन्हें पुन: संकलित करने की आवश्यकता नहीं है, और कई बार यह ऐसा कर सकता है जिससे एक प्रणाली को चुस्त किया जा सके। #includeहेडर में कोई फ़ाइल न रखें यदि हैडर को स्वयं उस अन्य हेडर फ़ाइल की आवश्यकता नहीं है।
  • प्रीप्रोसेसर प्रतीक जिनके इरादे प्रीप्रोसेसर के अलावा कुछ तंत्र, किसी भी तंत्र द्वारा पूरा किया जा सकता है।
  • बहुत सारी और संरचना परिभाषाएँ। उन्हें अलग हेडर में विभाजित करें।
  • उन कार्यों की इनलाइन परिभाषाएं जिनके लिए अतिरिक्त की आवश्यकता होती है #include, जो परिवर्तन के अधीन हैं, या जो बहुत बड़ी हैं। यदि कोई प्रशंसक बाहर है, और यदि उनके पास पंखे हैं, तो इनलाइन फ़ंक्शन बहुत कम होने चाहिए, यह हेडर में परिभाषित सामान के लिए स्थानीय होना चाहिए।

#includeबयानों का न्यूनतम सेट क्या बनता है?

यह एक निरर्थक प्रश्न है। एक TL; DR परिभाषा: एक हेडर फाइल में हेडर फाइलें शामिल होनी चाहिए जो सीधे इस्तेमाल किए जाने वाले प्रत्येक प्रकार को सीधे परिभाषित करती हैं या जो सीधे हेडर फाइल में प्रयुक्त प्रत्येक फ़ंक्शन को घोषित करती हैं, लेकिन इसमें कुछ और शामिल नहीं होना चाहिए। एक सूचक या सी ++ संदर्भ प्रकार प्रत्यक्ष उपयोग के रूप में योग्य नहीं है; आगे के संदर्भ पसंद किए जाते हैं।

एक gratuitous #includeनिर्देश के लिए एक जगह है , और यह एक स्वचालित परीक्षण में है। एक सॉफ्टवेयर पैकेज में हर हेडर फ़ाइल के लिए, मैं स्वचालित रूप से उत्पन्न करता हूं और फिर निम्नलिखित संकलन करता हूं:

#include "path/to/random/header_under_test"
int main () { return 0; }

संकलन साफ ​​होना चाहिए (यानी, किसी भी चेतावनी या त्रुटियों से मुक्त)। अपूर्ण प्रकारों या अज्ञात प्रकारों के बारे में चेतावनी या त्रुटियों का मतलब है कि परीक्षण के तहत हेडर फ़ाइल में कुछ लापता #includeनिर्देश और / या आगे की घोषणाएं गायब हैं। अच्छी तरह से नोट करें: सिर्फ इसलिए कि परीक्षा पास का मतलब यह नहीं है कि #includeनिर्देशों का सेट पर्याप्त है, अकेले कम से कम चलो।


इसलिए, अगर मेरे पास एक पुस्तकालय है जो एक संरचना को परिभाषित करता है, जिसे A कहा जाता है, और इस पुस्तकालय, जिसे B कहा जाता है, उस संरचना का उपयोग करता है, और लाइब्रेरी B का उपयोग प्रोग्राम C द्वारा किया जाता है, तो क्या मुझे लाइब्रेरी B के मुख्य शीर्षक में लाइब्रेरी A की शीर्ष लेख फ़ाइल शामिल करनी चाहिए, या चाहिए मैं अभी इसे घोषित करता हूं? पुस्तकालय A को संकलन के दौरान लाइब्रेरी B के साथ संकलित और लिंक किया गया है।
मार्कस जूल 11'18

@MarcusJ - एक हेडर में जो कुछ भी नहीं है, उसके तहत सूचीबद्ध सबसे पहली बात मैं आभार व्यक्त करता था। अगर हेडर फ़ाइल B हेडर फ़ाइल A में परिभाषाओं पर निर्भर नहीं करता है, तो हेडर फ़ाइल B. में #include हेडर फ़ाइल A को न डालें। हेडर फ़ाइल तीसरे पक्ष की निर्भरता को निर्दिष्ट करने या निर्देशों का निर्माण करने का स्थान नहीं है। वे कहीं और जाते हैं जैसे कि एक शीर्ष-स्तरीय रीडमी फ़ाइल।
डेविड हैम्मन

1
@MarcusJ - मैंने आपके प्रश्न का उत्तर देने के प्रयास में अपना उत्तर अपडेट किया। ध्यान दें कि आपके प्रश्न का एक उत्तर नहीं है। मैं चरम सीमाओं के एक जोड़े के साथ वर्णन करता हूँ। केस 1: लाइब्रेरी बी सोर्स लाइब्रेरी में ए केवल लाइब्रेरी ए की कार्यक्षमता का उपयोग करने वाली एकमात्र जगह है। केस 2: लाइब्रेरी A में लाइब्रेरी B में टाइप ए और / या फ़ंक्शंस का उपयोग करते हुए सीधे लाइब्रेरी बी के लिए हेडर फ़ाइल (एस) के साथ लाइब्रेरी ए में कार्यक्षमता का एक पतला विस्तार है। मामले 1 में, लाइब्रेरी ए को उजागर करने का कोई कारण नहीं है। पुस्तकालय बी के लिए हेडर (ओं) के मामले में, यह एक्सपोज़र बहुत अनिवार्य है।
डेविड हैम्मन

हाँ यह मामला 2 है, क्षमा करें मेरी टिप्पणी इस तथ्य पर छोड़ दी गई है कि यह लाइब्रेरी बी के हेडर में पुस्तकालय ए में घोषित प्रकारों का उपयोग कर रहा है, मैं सोच रहा था कि मैं इसे घोषित करने में सक्षम हो सकता हूं, लेकिन मुझे नहीं लगता कि यह काम होने वाला है। अद्यतन के लिए धन्यवाद।
मार्कस जे।

क्या हेडर फ़ाइल में स्थिरांक जोड़ना एक बड़ी संख्या है?
mding5692

15

इसके अलावा जो पहले ही कहा जा चुका है।

एच फ़ाइलों में हमेशा शामिल होना चाहिए:

  • स्रोत कोड प्रलेखन !!! कम से कम, कार्यों के विभिन्न मापदंडों और वापसी मूल्यों का उद्देश्य क्या है।
  • हैडर गार्ड, #ifndef MYHEADER_H #define MYHEADER_H ... #endif

एच फाइलों में कभी भी नहीं होना चाहिए:

  • डेटा आवंटन का कोई भी रूप।
  • कार्य की परिभाषा। कुछ मामलों में इनलाइन फ़ंक्शन एक दुर्लभ अपवाद हो सकते हैं।
  • कुछ भी लेबल static
  • टाइप्डिफ़्स, # वेडाइन या स्थिरांक जिनकी शेष एप्लिकेशन के लिए कोई प्रासंगिकता नहीं है।

(मैं यह भी कहूंगा कि गैर-स्थिर वैश्विक / बाहरी चर का उपयोग करने का कोई कारण नहीं है, कहीं भी, लेकिन यह किसी भी पोस्ट के लिए चर्चा है।)


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

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

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

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

2
प्रलेखन के लिए थोड़ा सा बेल्ड, लेकिन +1। यह वर्ग क्यों मौजूद है? कोड खुद के लिए नहीं बोलता है। यह कार्य क्या करता है? RTFC (फाइन .cpp फ़ाइल पढ़ें) एक अश्लील चार अक्षर का संक्षिप्त नाम है। समझने के लिए कभी भी RTFC नहीं होना चाहिए। हेडर में प्रोटोटाइप संक्षेप में होना चाहिए, कुछ निकालने योग्य टिप्पणी (जैसे, डॉक्सीजन) में, क्या तर्क हैं और फ़ंक्शन क्या करता है। यह डेटा सदस्य क्यों मौजूद है, इसमें क्या शामिल है, और मीटर, पैर या फर्लांग में मान है? वह भी टिप्पणियों के लिए एक और विषय है (हटाने योग्य) मौजूद हैं।
डेविड हैमेन

4

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

मैक्रोज़, इनलाइन फ़ंक्शंस और टेम्पलेट डेटा या कोड की तरह लग सकते हैं, लेकिन वे कोड उत्पन्न नहीं करते हैं क्योंकि वे पार्स होते हैं, लेकिन इसके बजाय जब वे उपयोग किए जाते हैं। इन वस्तुओं को अक्सर एक .c या .cpp से अधिक में उपयोग करने की आवश्यकता होती है, इसलिए वे .h से संबंधित होते हैं।

मेरे विचार में, हेडर फ़ाइल में संबंधित .c या .cpp के लिए न्यूनतम व्यावहारिक इंटरफ़ेस होना चाहिए। इंटरफ़ेस में वैश्विक चर के लिए #defines, class, typedef, संरचना परिभाषाएँ, फ़ंक्शन प्रोटोटाइप और कम पसंदीदा, बाहरी परिभाषाएं शामिल हो सकती हैं। हालाँकि, यदि किसी घोषणा को केवल एक स्रोत फ़ाइल में उपयोग किया जाता है, तो इसे संभवतः .h से बाहर रखा जाना चाहिए और इसके बजाय स्रोत फ़ाइल में समाहित किया जाना चाहिए।

कुछ असहमत हो सकते हैं, लेकिन .h फ़ाइलों के लिए मेरा व्यक्तिगत मानदंड यह है कि वे # अन्य सभी .h फ़ाइलों को हटा दें, जिन्हें उन्हें संकलित करने में सक्षम होने की आवश्यकता है। कुछ मामलों में, यह बहुत सारी फाइलें हो सकती हैं, इसलिए हमारे पास बाहरी निर्भरता को कम करने के लिए कुछ प्रभावी तरीके हैं जैसे कि कक्षाओं के लिए आगे की घोषणाएं जो हमें कक्षा के ऑब्जेक्ट्स में पॉइंटर्स का उपयोग किए बिना यह शामिल करती हैं कि क्या फ़ाइलों को शामिल करने का एक बड़ा पेड़ हो सकता है।


3

हैडर फ़ाइल में निम्नलिखित संगठन होना चाहिए:

  • प्रकार और निरंतर परिभाषा
  • बाहरी वस्तु घोषणाएं
  • बाहरी फ़ंक्शन की घोषणा

हेडर फ़ाइलों में ऑब्जेक्ट परिभाषाएँ नहीं होनी चाहिए, केवल परिभाषाएँ और ऑब्जेक्ट घोषणाएँ।


इनलाइन फ़ंक्शन परिभाषाओं के बारे में क्या?
कोस

यदि इनलाइन फ़ंक्शन एक "सहायक" फ़ंक्शन है जो केवल एक सी मॉड्यूल के अंदर उपयोग किया जाता है, तो इसे केवल .c फ़ाइल में डालें। यदि, इनलाइन फ़ंक्शन दो या अधिक मॉड्यूल के लिए दृश्यमान होना चाहिए, तो इसे हेडर फ़ाइल के अंदर रखें।
thed

साथ ही, यदि फ़ंक्शन को लाइब्रेरी की सीमा के पार दिखाई दे रहा है, तो इसे इनलाइन न करें क्योंकि यह उन सभी को मजबूर करता है जो लाइब्रेरी का उपयोग करते हुए हर बार चीजों को संशोधित करते हैं।
डोनल फैलो

@ डोनल फेलो: यह एक बैकहैंडेड समाधान है। एक बेहतर नियम: हेडर में सामान न रखें जो बार-बार संशोधन के अधीन है। हेडर में एक छोटे से फ़ंक्शन को कम करने के साथ कुछ भी गलत नहीं है यदि फ़ंक्शन में कोई प्रशंसक नहीं है और एक स्पष्ट परिभाषा है जो केवल तभी बदल जाएगी जब अंतर्निहित डेटा संरचना बदल जाती है। यदि फ़ंक्शन की परिभाषा बदल जाती है क्योंकि अंतर्निहित संरचना की परिभाषा बदल गई है, तो हाँ, आपको सब कुछ फिर से शुरू करना होगा, लेकिन आपके पास ऐसा करने की आवश्यकता है क्योंकि संरचना की परिभाषा बदल गई है।
डेविड हेमेन

0

वे कथन जो डेटा और कोड उत्पन्न करते हैं, जैसे कि वे पार्स किए गए हैं, किसी .hफ़ाइल में नहीं होना चाहिए । जहां तक ​​मेरी बात है, हेडर फाइल में केवल न्यूनतम व्यावहारिक इंटरफ़ेस से संबंधित .cया होनी चाहिए .cpp

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.