C Language
हेडर फाइल्स बनाएं और शामिल करें
खोज…
परिचय
आधुनिक सी में, हेडर फाइलें महत्वपूर्ण उपकरण हैं जिन्हें सही ढंग से डिजाइन और उपयोग किया जाना चाहिए। वे संकलक को एक कार्यक्रम के स्वतंत्र रूप से संकलित भागों की जांच करने की अनुमति देते हैं।
हेडर, प्रकार, फ़ंक्शन, मैक्रोज़ आदि की घोषणा करते हैं जो कि सुविधाओं के एक सेट के उपभोक्ताओं द्वारा आवश्यक हैं। उन सभी सुविधाओं का उपयोग करने वाले सभी कोड में हेडर शामिल हैं। उन सुविधाओं को परिभाषित करने वाले सभी कोड में हेडर शामिल हैं। यह संकलक को जांचने की अनुमति देता है कि उपयोग और परिभाषाएं मेल खाती हैं।
परिचय
C प्रोजेक्ट में हेडर फाइल बनाते और उपयोग करते समय कई दिशानिर्देशों का पालन करना होता है:
Idemopotence
यदि अनुवाद इकाई (टीयू) में हेडर फ़ाइल कई बार शामिल की जाती है, तो उसे बिल्ड नहीं तोड़ना चाहिए।
स्व रोकथाम
यदि आपको हेडर फ़ाइल में घोषित सुविधाओं की आवश्यकता है, तो आपको किसी अन्य हेडर को स्पष्ट रूप से शामिल नहीं करना चाहिए।
Minimality
आप किसी भी हेडर से किसी भी जानकारी को हटाने में सक्षम नहीं होना चाहिए, क्योंकि यह विफल होता है।
आप क्या उपयोग करते हैं (IWYU) शामिल करें
C से C ++ के लिए अधिक चिंता की बात है, लेकिन फिर भी C में महत्वपूर्ण है। यदि TU में कोड (इसे
code.c
कॉल करता है) सीधे एक हेडर द्वारा घोषित सुविधाओं का उपयोग करता है (इसे"headerA.h"
शीर्ष लेख"headerA.h"
), तोcode.c
को सीधे#include "headerA.h"
करना चाहिए, भले ही टीयू शामिल हो। एक और हेडर (इसे"headerB.h"
) जो कि इस समय,"headerA.h"
को शामिल करने के लिए होता है।
कभी-कभी, इन दिशानिर्देशों में से एक या एक से अधिक को तोड़ने के लिए पर्याप्त पर्याप्त कारण हो सकते हैं, लेकिन आपको दोनों को पता होना चाहिए कि आप नियम तोड़ रहे हैं और ऐसा करने से पहले आपको ऐसा करने के परिणामों के बारे में पता होना चाहिए।
Idempotence
यदि किसी विशेष हेडर फ़ाइल को अनुवाद इकाई (टीयू) में एक से अधिक बार शामिल किया जाता है, तो कोई संकलन समस्याएं नहीं होनी चाहिए। इसे id इडम्पोटेंस ’की संज्ञा दी जाती है; आपके शीर्षलेखों को उदासीन होना चाहिए। सोचो कितना मुश्किल जीवन है, तो आप यह सुनिश्चित करना था कि हो सकता है #include <stdio.h>
केवल एक बार शामिल किया गया था।
आलस्य को प्राप्त करने के दो तरीके हैं: हेडर गार्ड और #pragma once
निर्देश।
हेडर गार्ड
हेडर गार्ड सरल और विश्वसनीय हैं और सी मानक के अनुरूप हैं। हेडर फ़ाइल में पहली गैर-टिप्पणी लाइनें फॉर्म की होनी चाहिए:
#ifndef UNIQUE_ID_FOR_HEADER
#define UNIQUE_ID_FOR_HEADER
अंतिम गैर-टिप्पणी लाइन #endif
होनी चाहिए, वैकल्पिक रूप से इसके बाद एक टिप्पणी के साथ:
#endif /* UNIQUE_ID_FOR_HEADER */
इन #include
लाइनों के बीच अन्य #include
निर्देशों सहित सभी परिचालनात्मक कोड होने चाहिए।
प्रत्येक नाम अद्वितीय होना चाहिए। अक्सर, एक नाम योजना जैसे HEADER_H_INCLUDED
का उपयोग किया जाता है। कुछ पुराने कोड हेडर गार्ड (उदाहरण के लिए #ifndef BUFSIZ
<stdio.h>
में #ifndef BUFSIZ
) के रूप में परिभाषित प्रतीक का उपयोग करते हैं, लेकिन यह एक अद्वितीय नाम जितना विश्वसनीय नहीं है।
एक विकल्प हेडर गार्ड नाम के लिए एक उत्पन्न एमडी 5 (या अन्य) हैश का उपयोग करना होगा। आपको सिस्टम हेडर द्वारा उपयोग की जाने वाली योजनाओं का अनुकरण करने से बचना चाहिए जो अक्सर कार्यान्वयन के लिए आरक्षित नामों का उपयोग करते हैं - एक अंडरस्कोर से शुरू होने वाले नाम या तो किसी अन्य अंडरस्कोर या ऊपरी-केस पत्र के बाद।
#pragma once
निर्देशन
वैकल्पिक रूप से, कुछ कंपाइलर #pragma once
निर्देश का समर्थन करते हैं जिसका हेडर गार्ड के लिए दिखाई गई तीन लाइनों के समान प्रभाव पड़ता है।
#pragma once
जो कंपाइलर #pragma once
सपोर्ट करते हैं, उनमें #pragma once
MS Visual Studio और GCC और Clang शामिल हैं। हालांकि, अगर पोर्टेबिलिटी एक चिंता है, तो हेडर गार्ड का उपयोग करना बेहतर है, या दोनों का उपयोग करें। आधुनिक संकलक (जो C89 या बाद वाले का समर्थन करते हैं) को टिप्पणी के बिना, नजरअंदाज करने की आवश्यकता होती है, कि वे पहचान नहीं करते हैं ('किसी भी तरह का ऐसा व्यवहार जिसे मान्यता नहीं मिली है, उसे नजरअंदाज किया जाता है') लेकिन जीसीसी के पुराने संस्करण इतने अभिन्न नहीं थे।
स्व रोकथाम
आधुनिक हेडर आत्म निहित होना चाहिए, जिसका अर्थ है कि एक कार्यक्रम सुविधाओं से परिभाषित उपयोग करने के लिए है कि जरूरतों को header.h
कि हैडर (शामिल कर सकते हैं #include "header.h"
) और नहीं चिंता के बारे में अन्य हेडर पहले शामिल किया जाना चाहिए या नहीं।
सिफारिश: हेडर फाइलें स्व-निहित होनी चाहिए।
ऐतिहासिक नियम
ऐतिहासिक रूप से, यह एक हल्का विवादास्पद विषय रहा है।
एक बार एक और सहस्राब्दी पर, एटी एंड टी इंडियन हिल सी स्टाइल एंड कोडिंग मानकों में कहा गया है:
हेडर फ़ाइलों को नेस्टेड नहीं किया जाना चाहिए। हेडर फ़ाइल के लिए प्रस्तावना, इसलिए, वर्णन करना चाहिए कि हेडर के कार्यात्मक होने के लिए अन्य हेडर को
#include
d क्या होना चाहिए। चरम मामलों में, जहां बड़ी संख्या में हेडर फ़ाइलों को कई अलग-अलग स्रोत फ़ाइलों में शामिल किया जाना है, यह सभी आम#include
s को एक फ़ाइल#include
करने के लिए स्वीकार्य है।
यह आत्मसंतोष का विरोधी है।
आधुनिक नियम
हालाँकि, तब से, राय विपरीत दिशा में चल रही है। यदि किसी सोर्स फ़ाइल को हेडर हेडर द्वारा घोषित सुविधाओं का उपयोग करने की आवश्यकता होती है। header.h
, प्रोग्रामर को लिखने में सक्षम होना चाहिए:
#include "header.h"
और (केवल विषय सही खोज पथ कमांड लाइन पर सेट होने के लिए), किसी भी आवश्यक पूर्व-अपेक्षा हैडर के आधार पर शामिल किया जाएगा header.h
किसी भी आगे हेडर स्रोत फ़ाइल को जोड़ा गया जरूरत के बिना।
यह स्रोत कोड के लिए बेहतर मॉड्यूलरता प्रदान करता है। यह स्रोत को "अनुमान लगाता है कि यह हेडर क्यों जोड़ा गया था" से भी बचाता है कि कोड के संशोधित होने और एक या दो दशक तक हैक होने के बाद उत्पन्न होता है।
C के लिए NASA गोडार्ड स्पेस फ्लाइट सेंटर (GSFC) कोडिंग मानक अधिक आधुनिक मानकों में से एक है - लेकिन अब इसे ट्रैक करना थोड़ा कठिन है। इसमें कहा गया है कि हेडर स्व-निहित होना चाहिए। यह सुनिश्चित करने के लिए एक सरल तरीका भी प्रदान करता है कि हेडर स्व-निहित हैं: हेडर के लिए कार्यान्वयन फ़ाइल में हेडर को पहले हेडर के रूप में शामिल करना चाहिए। यदि यह स्व-निहित नहीं है, तो वह कोड संकलित नहीं होगा।
GSFC द्वारा दिए गए औचित्य में शामिल हैं:
§2.1.1 हैडर में तर्क शामिल हैं
इस मानक के लिए यूनिट हेडर के लिए आवश्यक अन्य सभी हेडर के लिए
#include
स्टेटमेंट को शामिल करने के लिए एक यूनिट के हेडर की आवश्यकता होती है। इकाई निकाय में इकाई हेडर के लिए#include
रखने से पहले कंपाइलर यह सत्यापित करता है कि हेडर में सभी आवश्यक#include
स्टेटमेंट हैं।
एक वैकल्पिक डिजाइन, इस मानक द्वारा अनुमत नहीं है, हेडर में कोई
#include
स्टेटमेंट की अनुमति नहीं देता है; सभी#includes
बॉडी फ़ाइलों में किए जाते हैं। यूनिट हेडर फाइल में तब #ifdef स्टेटमेंट होना चाहिए जो यह जांचे कि आवश्यक हेडर उचित क्रम में शामिल हैं।
वैकल्पिक डिजाइन का एक फायदा यह है कि बॉडी फ़ाइल में
#include
सूची एक मेकफाइल में आवश्यक निर्भरता सूची है, और इस सूची को कंपाइलर द्वारा जांचा जाता है। मानक डिज़ाइन के साथ, निर्भरता सूची बनाने के लिए एक उपकरण का उपयोग किया जाना चाहिए। हालाँकि, सभी अनुशंसित शाखाएं इस तरह के उपकरण प्रदान करती हैं।
वैकल्पिक डिजाइन का एक बड़ा नुकसान यह है कि यदि यूनिट की आवश्यक हेडर सूची में बदलाव होता है, तो उस यूनिट का उपयोग करने वाली प्रत्येक फ़ाइल को
#include
स्टेटमेंट सूची को अपडेट करने के लिए संपादित किया जाना चाहिए। इसके अलावा, एक संकलक पुस्तकालय इकाई के लिए आवश्यक हेडर सूची विभिन्न लक्ष्यों पर भिन्न हो सकती है।
वैकल्पिक डिजाइन का एक और नुकसान यह है कि कंपाइलर लाइब्रेरी हेडर फाइलें और अन्य तीसरे पक्ष की फाइलें आवश्यक
#ifdef
स्टेटमेंट को जोड़ने के लिए संशोधित की जानी चाहिए।
इस प्रकार, आत्म-नियंत्रण का मतलब है कि:
- एक हैडर तो
header.h
एक नया नेस्टेड हैडर जरूरतextra.h
, तो आप उस का उपयोग करता है हर स्रोत फ़ाइल की जाँच करने की जरूरत नहीं हैheader.h
कि क्या आप जोड़ने की जरूरत को देखने के लिएextra.h
। - एक हैडर तो
header.h
अब जरूरत है एक विशिष्ट शीर्ष लेख शामिल करने के लिएnotneeded.h
, तो आप हर स्रोत फ़ाइल की जाँच करने के लिए कि का उपयोग करता है की जरूरत नहीं हैheader.h
कि क्या आप सुरक्षित रूप से निकाल सकते हैं देखने के लिएnotneeded.h
(लेकिन देखना शामिल करें यदि क्या उपयोग । - आपको पूर्व-अपेक्षित हेडर (जिसमें ठीक से काम करने के लिए एक टोपोलॉजिकल प्रकार की आवश्यकता होती है) को शामिल करने के लिए सही अनुक्रम स्थापित करने की आवश्यकता नहीं है।
स्व-नियंत्रण की जाँच करना
देखें एक स्थिर पुस्तकालय के खिलाफ लिंकिंग एक स्क्रिप्ट के लिए chkhdr
कि परीक्षण idempotence और एक हेडर फाइल के आत्म-नियंत्रण के लिए इस्तेमाल किया जा सकता है।
Minimality
हेडर एक महत्वपूर्ण स्थिरता जाँच तंत्र हैं, लेकिन वे यथासंभव छोटे होने चाहिए। विशेष रूप से, इसका मतलब है कि एक हेडर में अन्य हेडर शामिल नहीं होने चाहिए क्योंकि कार्यान्वयन फ़ाइल को अन्य हेडर की आवश्यकता होगी। एक हेडर में केवल उन हेडर शामिल होने चाहिए जो वर्णित सेवाओं के उपभोक्ता के लिए आवश्यक हों।
उदाहरण के लिए, किसी प्रोजेक्ट हेडर में <stdio.h>
शामिल नहीं होना चाहिए जब तक कि फ़ंक्शन इंटरफ़ेस में से कोई एक FILE *
(या पूरी तरह से <stdio.h>
में परिभाषित अन्य प्रकारों में से एक) का उपयोग नहीं करता है। यदि कोई इंटरफ़ेस size_t
का उपयोग करता है, तो सबसे छोटा हेडर जो कि पर्याप्त है <stddef.h>
। जाहिर है, अगर size_t
को परिभाषित करने वाला एक और हेडर शामिल है, तो <stddef.h>
भी शामिल करने की कोई आवश्यकता नहीं है।
यदि शीर्ष लेख न्यूनतम हैं, तो यह संकलन समय को भी न्यूनतम रखता है।
हेडर को तैयार करना संभव है, जिसका एकमात्र उद्देश्य बहुत सारे अन्य हेडर को शामिल करना है। ये शायद ही कभी लंबे समय में एक अच्छा विचार बनते हैं क्योंकि कुछ स्रोत फ़ाइलों को वास्तव में सभी हेडर द्वारा वर्णित सभी सुविधाओं की आवश्यकता होगी। उदाहरण के लिए, एक <standard-ch>
तैयार किया जा सकता है जिसमें सभी मानक C हेडर शामिल हैं - देखभाल के साथ क्योंकि कुछ हेडर हमेशा मौजूद नहीं होते हैं। हालांकि, बहुत कम प्रोग्राम वास्तव में <locale.h>
या <tgmath.h>
की सुविधाओं का उपयोग करते हैं।
आप क्या उपयोग करते हैं (IWYU) शामिल करें
Google का शामिल करें आप क्या उपयोग करते हैं परियोजना, या IWYU, सुनिश्चित करता है कि स्रोत फ़ाइलों में कोड में उपयोग किए गए सभी हेडर शामिल हैं।
मान लीजिए कि एक स्रोत फ़ाइल source.c
में एक शीर्ष लेख arbitrary.h
शामिल है। जो बदले में संयोग से freeloader.h
शामिल करता है, लेकिन स्रोत फ़ाइल भी स्पष्ट रूप से और स्वतंत्र रूप से freeloader.h
से सुविधाओं का उपयोग करती है। शुरुआत करने के लिए सब ठीक है। फिर एक दिन arbitrary.h
बदल दिया जाता है ताकि उसके ग्राहकों को अब freeloader.h
की सुविधाओं की आवश्यकता न हो। अचानक, source.c
ने संकलन बंद कर दिया - क्योंकि यह IWYU मानदंडों को पूरा नहीं करता था। क्योंकि source.c
में कोड ने स्पष्ट रूप से freeloader.h
की सुविधाओं का उपयोग किया था, इसमें वह शामिल होना चाहिए जो इसका उपयोग करता है - स्रोत में भी एक स्पष्ट #include "freeloader.h"
होना चाहिए था। ( Idempotency ने सुनिश्चित किया है कि कोई समस्या नहीं थी।)
IWYU दर्शन उस संभावना को अधिकतम करता है जो कोड इंटरफेस में किए गए उचित परिवर्तनों के साथ भी संकलित करना जारी रखता है। स्पष्ट रूप से, यदि आपका कोड एक फ़ंक्शन को कॉल करता है जिसे बाद में प्रकाशित इंटरफ़ेस से हटा दिया गया है, तो तैयारी की कोई भी राशि आवश्यक परिवर्तन को रोक नहीं सकती है। यही कारण है कि जब संभव हो तो एपीआई में बदलाव से बचा जाता है, और क्यों कई रिलीज, आदि पर अपचयन चक्र होते हैं।
C ++ में यह एक विशेष समस्या है क्योंकि मानक हेडर को एक दूसरे को शामिल करने की अनुमति है। स्रोत फ़ाइल file.cpp
एक शीर्ष लेख शामिल हो सकते हैं header1.h
है कि एक मंच पर एक और शीर्ष लेख शामिल हैं header2.h
। file.cpp
की सुविधाओं का उपयोग करने के बाहर बदल सकता header2.h
रूप में अच्छी तरह। कोड संकलन है, क्योंकि - यह शुरू में एक समस्या नहीं होगी header1.h
शामिल header2.h
। एक और मंच, या वर्तमान मंच का एक उन्नत पर, header1.h
संशोधित किया जा सकता है जिससे अब वह भी शामिल है header2.h
, और फिर file.cpp
एक परिणाम के रूप संकलन बंद कर देंगे।
IWYU समस्या दिखाई देती है और सुझाव है कि होता header2.h
में सीधे शामिल किया जाना file.cpp
। यह सुनिश्चित करेगा कि यह संकलित होता रहे। अनुरूप विचार सी कोड पर भी लागू होते हैं।
संकेतन और मिसटेलनी
C मानक कहता है कि #include <header.h>
और #include "header.h"
बीच बहुत कम अंतर है।
[
#include <header.h>
] एक हेडर के लिए परिभाषित-परिभाषित स्थानों के अनुक्रम को विशिष्ट रूप से<
और>
सीमांकक के बीच निर्दिष्ट अनुक्रम द्वारा पहचाना जाता है, और हेडर की संपूर्ण सामग्री द्वारा उस निर्देश के प्रतिस्थापन का कारण बनता है। स्थानों को कैसे निर्दिष्ट किया जाता है या पहचाने जाने वाले शीर्षलेख कार्यान्वयन-परिभाषित है।
[
#include "header.h"
]"…"
सीमांकक के बीच निर्दिष्ट अनुक्रम द्वारा पहचानी गई स्रोत फ़ाइल की संपूर्ण सामग्री द्वारा उस निर्देश के प्रतिस्थापन का कारण बनता है। नामित स्रोत फ़ाइल को कार्यान्वयन-परिभाषित तरीके से खोजा जाता है। यदि यह खोज समर्थित नहीं है, या यदि खोज विफल हो जाती है, तो निर्देश पुन: प्रकाशित किया जाता है जैसे कि यह [#include <header.h>
]…
तो, डबल-कोटेड फॉर्म एंगल-ब्रैकेटेड फॉर्म की तुलना में अधिक स्थानों पर दिख सकता है। मानक उदाहरण द्वारा निर्दिष्ट करता है कि मानक शीर्षकों को कोण-कोष्ठक में शामिल किया जाना चाहिए, भले ही संकलन काम करता है यदि आप इसके बजाय दोहरे उद्धरण चिह्नों का उपयोग करते हैं। इसी तरह, POSIX जैसे मानक कोण-ब्रैकेट प्रारूप का उपयोग करते हैं - और आपको भी करना चाहिए। परियोजना द्वारा परिभाषित हेडर के लिए रिज़र्व डबल-हेडेड हेडर। बाहरी रूप से परिभाषित हेडर के लिए (आपकी परियोजना पर निर्भर अन्य परियोजनाओं से हेडर सहित), कोण-ब्रैकेट अंकन सबसे उपयुक्त है।
ध्यान दें कि #include
और हेडर के बीच एक स्थान होना चाहिए, भले ही कंपाइलर वहां कोई स्थान स्वीकार नहीं करेंगे। स्पेस सस्ते हैं।
कई परियोजनाएँ जैसे नोटेशन का उपयोग करती हैं:
#include <openssl/ssl.h>
#include <sys/stat.h>
#include <linux/kernel.h>
आपको यह विचार करना चाहिए कि क्या आपके प्रोजेक्ट में उस नेमस्पेस कंट्रोल का उपयोग करना है (यह संभवतः एक अच्छा विचार है)। आपको मौजूदा परियोजनाओं द्वारा उपयोग किए जाने वाले नामों को स्पष्ट करना चाहिए (विशेष रूप से, दोनों sys
और linux
खराब विकल्प होंगे)।
यदि आप इसका उपयोग करते हैं, तो आपका कोड नोटेशन के उपयोग में सावधान और सुसंगत होना चाहिए।
#include "../include/header.h"
संकेतन का उपयोग न करें।
यदि कभी चरों को परिभाषित किया जाता है तो हेडर फ़ाइलों को शायद ही कभी होना चाहिए। यद्यपि आप वैश्विक चर को न्यूनतम रखेंगे, यदि आपको वैश्विक चर की आवश्यकता है, तो आप इसे एक हेडर में घोषित करेंगे, और इसे एक उपयुक्त स्रोत फ़ाइल में परिभाषित करेंगे, और उस स्रोत फ़ाइल में शीर्षक को क्रॉस-चेक करने की घोषणा और परिभाषा शामिल होगी। , और चर का उपयोग करने वाली सभी स्रोत फाइलें इसे घोषित करने के लिए हेडर का उपयोग करेंगी।
कोरोलरी: आप स्रोत फ़ाइल में वैश्विक चर घोषित नहीं करेंगे - एक स्रोत फ़ाइल में केवल परिभाषाएँ होंगी।
हेडर फ़ाइलों को static inline
फ़ंक्शन की उल्लेखनीय अपवाद के साथ शायद ही कभी static
कार्यों की घोषणा करनी चाहिए, जो हेडर में परिभाषित किए जाएंगे यदि फ़ंक्शन एक से अधिक स्रोत फ़ाइल में आवश्यक हो।
- स्रोत फाइलें वैश्विक चर और वैश्विक कार्यों को परिभाषित करती हैं।
- स्रोत फ़ाइलें वैश्विक चर या कार्यों के अस्तित्व की घोषणा नहीं करती हैं; उनमें वे शीर्षलेख शामिल हैं जो चर या फ़ंक्शन की घोषणा करते हैं।
- हेडर फाइलें वैश्विक चर और फ़ंक्शन (और प्रकार और अन्य सहायक सामग्री) घोषित करती हैं।
- हेडर फाइलें चर (या
static
)inline
फ़ंक्शन को छोड़कर किसी भी फ़ंक्शन को परिभाषित नहीं करती हैं।
अन्य संदर्भ
- C में फ़ंक्शन कहाँ से करें?
- C और C ++ में मानक हेडर फ़ाइलों की सूची
-
static
याextern
बिनाinline
C99 में कभी उपयोगी है? - स्रोत फ़ाइलों के बीच चर साझा करने के लिए मैं
extern
उपयोग कैसे करूं? - एक हेडर के लिए एक रिश्तेदार पथ जैसे
"../include/header.h"
के क्या लाभ हैं? - हैडर समावेश अनुकूलन
- क्या मुझे हर हेडर शामिल करना चाहिए?