C++ में #include का रहस्य: <file> बनाम "file" — गति और अनुकूलन

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

परिचय: एक छोटी सी बात जो आपको संकलन के सेकंड खर्च करा सकती है

\n\n

कल्पना करें: आप एक C++ प्रोजेक्ट लिख रहे हैं। काम चल रहा है, कोड बढ़ रहा है, फ़ाइलों वाले फ़ोल्डर बढ़ रहे हैं। और तब आप फिर से #include टाइप करते हैं। हमेशा की तरह - कोण कोष्ठक में? या उद्धरण चिह्नों में? आखिरकार, क्या फर्क पड़ता है? कंपाइलर तो स्मार्ट है, खुद ढूंढ लेगा।

\n\n

स्पॉयलर: ढूंढ लेगा। लेकिन हमेशा जल्दी नहीं। और हमेशा वह फ़ाइल नहीं, जो आपके मन में थी। #include <filename> और #include "filename" के बीच अंतर का सवाल Stack Overflow पर सबसे लोकप्रिय में से एक है (सैकड़ों हज़ारों व्यूज़)। और यह सिर्फ सिंटैक्टिक शुगर का मामला नहीं है। यह संकलन प्रदर्शन, निर्भरताओं पर नियंत्रण और अंततः आपके कोड की गुणवत्ता का सवाल है।

\n\n

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

\n\n

प्रीप्रोसेसर कैसे काम करता है? #include निर्देश की शारीरिक रचना

\n\n

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

\n\n

यह सरल लगता है। लेकिन शैतान, हमेशा की तरह, विवरण में है। अर्थात्, प्रीप्रोसेसर इस फ़ाइल X को कहाँ खोजता है।

\n\n

कोण कोष्ठक: #include <filename>

\n

जब आप #include <iostream> लिखते हैं, तो प्रीप्रोसेसर विशेष रूप से मानक सिस्टम पथों पर खोज करने जाता है। Linux में यह आमतौर पर /usr/include, /usr/local/include और वे पथ होते हैं जो कंपाइलर को -I फ्लैग (या Visual Studio में /I) के माध्यम से दिए गए हैं।

\n

मुख्य बिंदु: प्रीप्रोसेसर वर्तमान प्रोजेक्ट निर्देशिका में नहीं देखता। केवल उन फ़ोल्डरों में जिन्हें 'सिस्टम' या 'इन्क्लूड खोजने के लिए' के रूप में निर्दिष्ट किया गया है।

\n

यह विशेष रूप से इसलिए किया गया है: ताकि मानक लाइब्रेरी के बजाय गलती से उसी नाम की स्थानीय फ़ाइल न उठा ली जाए।

\n\n

दोहरे उद्धरण: #include "filename"

\n

उद्धरण चिह्नों के साथ कहानी अधिक जटिल और दिलचस्प है। C++ मानक (धारा 16.2) कहता है: व्यवहार कार्यान्वयन-परिभाषित है। लेकिन व्यवहार में 99% कंपाइलर (GCC, Clang, MSVC) एक ही सिद्धांत पर काम करते हैं:

\n
    \n
  1. पहले उस निर्देशिका में खोजें जहाँ इन्क्लूड करने वाली फ़ाइल स्वयं स्थित है (आमतौर पर - स्रोत वाला वर्तमान फ़ोल्डर)।
  2. \n
  3. फिर उन्हीं पथों पर खोजें जो कोण कोष्ठक के लिए हैं (सिस्टम + -I)।
  4. \n
\n

अर्थात #include "myheader.h" पहले आपके main.cpp वाले फ़ोल्डर की जाँच करेगा। मिल गया - बढ़िया। नहीं मिला - सिस्टम सूची में जाएगा।

\n\n

यह सिर्फ ज्ञान है या वास्तविक अनुकूलन?

\n

'तो क्या? - आप पूछेंगे। - कंप्यूटर तेज़ हैं, कहाँ खोजने से क्या फर्क पड़ता है?'

\n

फर्क है, और यह दो कारकों से बनता है: खोज की गति और इरादों की स्पष्टता।

\n\n

कारक 1: फ़ाइल खोज की गति

\n

एक छोटे प्रोजेक्ट (10-20 फ़ाइलें) में आपको अंतर नज़र नहीं आएगा। लेकिन एक वास्तविक enterprise उत्पाद या गेम इंजन में इन्क्लूड की संख्या दसियों हज़ार से अधिक हो सकती है। हर बार जब आप #include "some_system_lib.h" लिखते हैं, तो प्रीप्रोसेसर वर्तमान फ़ोल्डर और सभी उप-फ़ोल्डरों की जाँच करने में अतिरिक्त समय बर्बाद करता है (कार्यान्वयन पर निर्भर करता है)।

\n

जीवन से एक उदाहरण: कल्पना करें कि आपके पास 10,000 फ़ाइलों वाला एक प्रोजेक्ट है। उनमें से 20% मानक लाइब्रेरी के लिए उद्धरण चिह्नों का उपयोग करते हैं। ऐसा प्रत्येक इन्क्लूज़ वर्तमान निर्देशिका में एक अतिरिक्त सिस्टम कॉल stat() या access() करता है। ये माइक्रोसेकंड हैं, लेकिन पूरे प्रोजेक्ट पर कुल मिलाकर - संकलन के वास्तविक सेकंड।

\n\n

#include <iostream> का उपयोग #include "iostream" के बजाय यह सुनिश्चित करता है कि खोज सीधे सिस्टम पथों से शुरू हो, स्थानीय निर्देशिका को छोड़कर। यह देता है

ब्लॉग

पुस्तक अनुशंसाएँ