C ++ में एक्सटर्नल का उपयोग कब करें


398

मैं "C ++ में सोचता हूं" पढ़ रहा हूं और यह सिर्फ externघोषणा को पेश करता है । उदाहरण के लिए:

extern int x;
extern float y;

मुझे लगता है कि मैं अर्थ (परिभाषा के बिना घोषणा) को समझता हूं, लेकिन मुझे आश्चर्य है कि जब यह उपयोगी साबित होता है।

क्या कोई उदाहरण दे सकता है?


1
मुझे externकई मौकों पर एक परिभाषा प्रदान करनी है । Microsoft उपकरण अनुपलब्ध प्रतीकों के लिए एक लिंक त्रुटि उत्पन्न करते हैं जब किसी अन्य स्रोत फ़ाइल में तालिकाओं को केवल परिभाषित किया गया था। समस्या यह थी, तालिका थी constऔर सी ++ संकलक ने staticअनुवाद इकाई में इसे बढ़ावा दिया । उदाहरण के लिए देखें, ariatab.cppऔर kalynatab.cpp
jww

2
और मुझे लगता है कि निक का उत्तर सही है क्योंकि वह एकमात्र ऐसा व्यक्ति है जिसने C ++ प्रश्न का उत्तर दिया है। हर कोई एक सी सवाल को पचा गया प्रतीत होता है।
jww

जवाबों:


519

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

स्पष्ट करने के लिए, का उपयोग कर extern int x;संकलक कि प्रकार का ऑब्जेक्ट बताता है intकहा जाता है xमौजूद है कहीं । यह जानने के लिए संकलक का काम नहीं है कि यह कहां मौजूद है, इसे केवल प्रकार और नाम जानने की जरूरत है ताकि यह जान सके कि इसका उपयोग कैसे करना है। एक बार सभी स्रोत फ़ाइलों को संकलित कर लेने के बाद, लिंकर xएक परिभाषा के सभी संदर्भों को हल करेगा जो इसे संकलित स्रोत फ़ाइलों में से एक में पाता है। इसे काम करने के लिए, xचर की परिभाषा को "बाहरी लिंकेज" कहा जाना चाहिए, जिसका मूल रूप से यह मतलब है कि इसे एक फ़ंक्शन के बाहर घोषित किया जाना चाहिए (जिसे आमतौर पर "फ़ाइल स्कोप" कहा जाता है) और staticकीवर्ड के बिना ।

शीर्ष लेख:

#ifndef HEADER_H
#define HEADER_H

// any source file that includes this will be able to use "global_x"
extern int global_x;

void print_global_x();

#endif

स्रोत 1:

#include "header.h"

// since global_x still needs to be defined somewhere,
// we define it (for example) in this source file
int global_x;

int main()
{
    //set global_x here:
    global_x = 5;

    print_global_x();
}

स्रोत 2:

#include <iostream>
#include "header.h"

void print_global_x()
{
    //print global_x here:
    std::cout << global_x << std::endl;
}

15
धन्यवाद। तो, अगर मैं बाहरी कीवर्ड के बिना हेडर फ़ाइल में एक वैश्विक चर घोषित करता हूं, तो स्रोत फ़ाइलों में हेडर शामिल नहीं है?
असलान 986

23
आपको हेडर में वैश्विक संस्करण घोषित नहीं करना चाहिए, क्योंकि तब जब 2 फ़ाइलों में एक ही हेडर फ़ाइल शामिल होती है, तो यह लिंक नहीं करेगा (लिंकर "डुप्लिकेट प्रतीक" के बारे में एक त्रुटि का उत्सर्जन करेगा)
kuba

63
@ Aslan986: नहीं, कुछ बुरा होता है। हेडर में शामिल प्रत्येक स्रोत फ़ाइल का अपना चर होगा, इसलिए प्रत्येक स्रोत फ़ाइल स्वतंत्र रूप से संकलन करेगी लेकिन लिंकर शिकायत करेगा क्योंकि दो स्रोत फ़ाइलों में एक ही वैश्विक पहचानकर्ता होंगे।
ड्रीमलैक्स

7
जब आप "बाहरी" शब्द का उपयोग नहीं करते हैं, तो अब चर मौजूद है। जब आप "एक्सटर्नल" का उपयोग करते हैं, तो यह एक "अरे है यह संस्करण कहीं और है"। जवाब देने के बारे में खेद है कि क्या यह एक परिभाषा या घोषणा है, क्योंकि मैं हमेशा इन दोनों के बारे में भ्रमित हूं।
कुबा

3
@CCJ: इसमें शामिल गार्ड केवल स्रोत फ़ाइल के लिए काम करता है जो इसमें शामिल है। यह एक ही हेडर को एक ही स्रोत फ़ाइल के भीतर दो बार शामिल किया जाना बंद कर देता है (बस यदि अन्य हेडर भी इसमें शामिल हैं आदि)। इसलिए गार्ड्स को भी शामिल करें, प्रत्येक स्रोत फ़ाइल जिसमें हेडर शामिल है उसकी अभी भी अपनी परिभाषा होगी।
ड्रीमलैक्स

172

यह उपयोगी है जब आप कुछ मॉड्यूल के बीच एक चर साझा करते हैं। आप इसे एक मॉड्यूल में परिभाषित करते हैं, और दूसरों में बाहरी उपयोग करते हैं।

उदाहरण के लिए:

file1.cpp में:

int global_int = 1;

file2.cpp में:

extern int global_int;
//in some function
cout << "global_int = " << global_int;

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

1
क्या कोई गैचा है जब नामस्थान शामिल हैं, global_intवैश्विक नामस्थान में है, अगर मुझे इसे file2.cpp में उपयोग करना था तो कुछ नामस्थान अनुभाग में मुझे इसे सही करने की गुंजाइश होगी? यानीnamespace XYZ{ void foo(){ ::global_int++ } };
jxramos

8
@Zac: दूसरी ओर, हेडर में एक वैश्विक चर घोषित नहीं करके, आपने अनजाने में यह निर्धारित करना अधिक कठिन बना दिया है कि यह वास्तव में कहां परिभाषित किया गया है। आमतौर पर यदि आप एक वैश्विक चर को घोषित करते हुए देखते हैं abc.h, तो यह एक अच्छा मौका है जिसे इसमें परिभाषित किया जाएगा abc.cpp। एक अच्छा आईडीई हमेशा मदद करेगा, लेकिन सुव्यवस्थित कोड हमेशा एक बेहतर समाधान होता है।
ड्रीमलैक्स

externfile2.cpp में बिना , अभी भी global_intशामिल करने के बाद उपयोग कर सकते हैं। मुझे इसकी आवश्यकता क्यों है?
टॉमसॉयर

62

यह सब संबंध के बारे में है

पिछले उत्तरों ने अच्छी व्याख्याएँ दीं extern

लेकिन मैं एक महत्वपूर्ण बिंदु जोड़ना चाहता हूं।

आप के बारे में पूछने externमें C ++ में नहीं सी और मैं नहीं जानता कि क्यों किसी भी हालत के बारे में उल्लेख जवाब नहीं है जब externके साथ आता है constC ++।

C ++ में, एक constचर में डिफ़ॉल्ट रूप से आंतरिक लिंकेज होता है (सी की तरह नहीं)।

तो यह परिदृश्य लिंकिंग त्रुटि की ओर ले जाएगा :

स्रोत 1:

const int global = 255; //wrong way to make a definition of global const variable in C++

स्रोत 2:

extern const int global; //declaration

इसे इस तरह होना चाहिए:

स्रोत 1:

extern const int global = 255; //a definition of global const variable in C++

स्रोत 2:

extern const int global; //declaration

2
यह गलत क्यों है क्योंकि यह परिभाषा भाग में 'बाहरी' को शामिल किए बिना सी ++ में काम करता है?
चीफ शिफ्टर

1
मुझे लगता है कि दृश्य माइक्रो के साथ छठे स्टूडियो में उस लिंकिंग त्रुटि का सामना नहीं करना पड़ता है। मैं क्या खो रहा हूँ?
क्रेग.फाइड

1
@ lartist93 @ Craig.Feied मेरा मानना ​​है कि आपको फिर से सावधानीपूर्वक जांच करने की आवश्यकता हो सकती है। यहां तक ​​कि अगर संकलक भी त्रुटि को जोड़ने की सूचना नहीं देता है, तो क्या आप जांच सकते हैं कि दोनों स्रोत में दोनों वस्तुएं externपरिभाषा के बिना समान हैं ? आप ऐसा कर सकते हैं globalस्रोत 2 के मूल्य को प्रिंट करके ।
ट्रेवर

3
पुष्टि करें, यदि MSVS 2018 में कोई लिंकिंग त्रुटि है तो externछोड़ दिया गया है const int global = 255;
Evg

13

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


वैसे भी यह बहुत OOP ध्वनि नहीं करता है, मैं उन्हें एक सिंगलटन क्लास में डालूंगा ... या एक स्थानीय स्थैतिक मूल्य वापस करने वाला एक फ़ंक्शन ...
RzR
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.