एक परिभाषा और एक घोषणा के बीच क्या अंतर है?


857

दोनों का अर्थ मुझे खटकता है।


91
@Lasse: सच नहीं है। एक परिभाषा दोनों को परिभाषित और घोषित करती है ;-)
स्टीव जेसप

13
सच कहूं, तो मुझे सीखने में बहुत परेशानी हुई जो कि थी, इसलिए मुझे नाम स्पष्ट नहीं लगे। मुझे अर्थ के साथ कोई समस्या नहीं थी, सिर्फ अर्थ के साथ जुड़ने के लिए।
डेविड थोरले

6
फिर भी, यह एक डुप्लिकेट प्रश्न नहीं है, क्योंकि यह C / C ++ के बारे में पूछता है, जबकि यह कि अन्य प्रश्न सभी भाषाओं के बारे में पूछा जाता है, या सामान्य रूप से कोई भी नहीं। इसका केवल डुप्लिकेट उत्तर है (क्योंकि उस अन्य प्रश्न में, कुछ उत्तरों ने C और / या C ++ को छोड़कर सभी भाषा को अनदेखा करना चुना)।
स्टीव जेसप 11'09

5
@DavidThornley मैं इस चाल का उपयोग करें: एक परिभाषा एक देता महीन एक दिया चर या समारोह के विवरण। इसे याद रखने के लिए, मुझे याद है कि "परिभाषा" शब्द के मध्य में "महीन" शब्द का सादृश्य है। :)
मार्को लेओग्रांडे

4
कमाल है कि इस सवाल पर कितना बकवास है। बस यह दिखाने के लिए जाता है कि इस भाषा को कितना गलत समझा गया है, और कैसे उन गलतफहमियों को नियमित रूप से प्रचारित किया जाता है । यह वास्तव में दुखद है।
१०:४० पर ऑर्बिट

जवाबों:


858

एक घोषणा एक पहचानकर्ता का परिचय देती है और इसके प्रकार का वर्णन करती है, यह एक प्रकार, वस्तु या कार्य है। एक घोषणा है कि संकलक को उस पहचानकर्ता के संदर्भों को स्वीकार करने की आवश्यकता है। ये घोषणाएँ हैं:

extern int bar;
extern int g(int, int);
double f(int, double); // extern can be omitted for function declarations
class foo; // no extern allowed for type declarations

एक परिभाषा वास्तव में इस पहचानकर्ता को तत्काल / लागू करती है। यह उन संस्थाओं के संदर्भ को जोड़ने के लिए लिंकर की जरूरत है। ये उपरोक्त घोषणाओं के अनुरूप हैं:

int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
class foo {};

एक घोषणा के स्थान पर एक परिभाषा का उपयोग किया जा सकता है।

एक पहचानकर्ता को जितनी बार चाहें उतनी बार घोषित किया जा सकता है । इस प्रकार, C और C ++ में निम्नलिखित कानूनी है:

double f(int, double);
double f(int, double);
extern double f(int, double); // the same as the two above
extern double f(int, double);

हालाँकि, इसे ठीक एक बार परिभाषित किया जाना चाहिए । यदि आप किसी ऐसी चीज़ को परिभाषित करना भूल जाते हैं जिसे घोषित किया गया है और कहीं पर संदर्भित किया गया है, तो लिंक करने वाले को यह नहीं पता होता है कि संदर्भों को लिंक करना क्या है और एक लापता प्रतीकों के बारे में शिकायत करता है। यदि आप किसी चीज़ को एक से अधिक बार परिभाषित करते हैं, तो लिंकर को यह नहीं पता होता है कि कौन सी परिभाषाएँ संदर्भों को लिंक करने और नकली प्रतीकों के बारे में शिकायत करती हैं।


बहस के बाद से सी ++ में एक वर्ग की घोषणा बनाम कक्षा की परिभाषा क्या है (अन्य सवालों के जवाब और टिप्पणियों में) सामने आती रहती है, मैं यहां सी ++ मानक से एक उद्धरण पेस्ट करूंगा।
3.1 / 2 पर, C ++ 03 कहता है:

एक घोषणा एक परिभाषा है जब तक कि यह [...] एक वर्ग नाम की घोषणा नहीं है [...]।

3.1 / 3 तो कुछ उदाहरण देता है। उन लोगों के बीच:

[उदाहरण: [...]
संरचना S {int a; इंट बी; }; // एस, एस :: ए, और एस :: बी [...] को परिभाषित करता है
संरचना एस; // एस घोषित करता है
उदाहरण के लिए

इसे योग करने के लिए: C ++ मानक struct x;एक घोषणा और struct x {};एक परिभाषा मानता है । (दूसरे शब्दों में, "आगे की घोषणा" एक मिथ्या नाम है , क्योंकि C ++ में वर्ग घोषणाओं के अन्य रूप नहीं हैं।)

Litb (जोहान्स शाउब) का धन्यवाद जिसने वास्तविक अध्याय को खोद दिया और अपने उत्तर में एक कविता लिखी।


2
@unknown: या तो आपका कंपाइलर टूट गया है आपके पास गलत तरीके से कॉपी किया गया sbi का कोड है। उदाहरण के लिए, N1124 में 6.7.2 (2): "सभी घोषणाएं जो एक ही वस्तु या फ़ंक्शन को संदर्भित करती हैं, उनके पास संगत प्रकार होगा, अन्यथा, व्यवहार अपरिभाषित है।"
स्टीव जेसप

4
@ ब्रायन: "एक्सट्रीम इंट आई;" कहते हैं कि मैं कहीं न कहीं एक int हूं, इसके बारे में चिंता न करें "मुझे पता है?" इसका मतलब है कि मैं एक अंतर है, और इसका पता और दायरा यहां निर्धारित किया गया है।
डेविड थॉर्नले

12
@ ब्रायन: तुम गलत हो। extern int iएक घोषणा है, क्योंकि यह सिर्फ परिचय / निर्दिष्ट करता है i। आप extern int iप्रत्येक संकलन इकाई में जितने चाहें उतने हो सकते हैं। int iहालाँकि, एक परिभाषा है। यह पूर्णांक के लिए इस अनुवाद इकाई में स्थान को दर्शाता है और लिंकर को iइस इकाई के खिलाफ सभी संदर्भों को जोड़ने की सलाह देता है । यदि आपके पास इनमें से एक परिभाषा से अधिक या कम है, तो लिंकर शिकायत करेगा।
sbi

4
int i;फ़ाइल / वैश्विक दायरे या फ़ंक्शन दायरे में @Brian C और C ++ दोनों में एक परिभाषा है। C में क्योंकि यह स्टोरेज को आवंटित करता है, और C ++ में क्योंकि इसमें एक्सटर्नल स्पेसियर या लिंकेज-स्पेसिफिकेशन नहीं है। यह राशि उसी चीज के लिए है, जिसे sbi कहते हैं: दोनों ही मामलों में यह घोषणा उस वस्तु को निर्दिष्ट करती है, जिसमें उस दायरे में "i" के सभी संदर्भों को जोड़ा जाना चाहिए।
स्टीव जेसोप

4
@unknown, सावधान रहें कि आप सदस्यों को कक्षा के दायरे में दोबारा नहीं ला सकते हैं : struct A { double f(int, double); double f(int, double); };अमान्य, निश्चित रूप से। यह कहीं और की अनुमति है। कुछ ऐसे स्थान हैं जहाँ आप चीजों की घोषणा कर सकते हैं, लेकिन परिभाषित नहीं, बहुत: void f() { void g(); }मान्य, लेकिन निम्नलिखित नहीं void f() { void g() { } };:। एक परिभाषा क्या है और क्या घोषणा के सूक्ष्म नियम हैं जब यह टेम्पलेट्स की बात आती है - सावधान! एक अच्छा जवाब के लिए हालांकि +1।
जोहान्स स्काउब -

168

C ++ मानक खंड 3.1 से:

एक घोषणा एक अनुवाद इकाई में नामों का परिचय देती है या पिछले घोषणाओं द्वारा शुरू किए गए नामों को पुन: प्रकाशित करती है। एक घोषणा इन नामों की व्याख्या और विशेषताओं को निर्दिष्ट करती है।

अगले पैराग्राफ में कहा गया है (मेरा जोर) कि एक घोषणा एक परिभाषा है जब तक ...

... यह फ़ंक्शन के शरीर को निर्दिष्ट किए बिना एक फ़ंक्शन की घोषणा करता है:

void sqrt(double);  // declares sqrt

... यह एक वर्ग परिभाषा के भीतर एक स्थिर सदस्य की घोषणा करता है:

struct X
{
    int a;         // defines a
    static int b;  // declares b
};

... यह एक वर्ग नाम घोषित करता है:

class Y;

... इसमें externएक इनिशलाइज़र या फ़ंक्शन बॉडी के बिना कीवर्ड होता है:

extern const int i = 0;  // defines i
extern int j;  // declares j
extern "C"
{
    void foo();  // declares foo
}

... या है typedefया usingबयान।

typedef long LONG_32;  // declares LONG_32
using namespace std;   // declares std

अब बड़े कारण के लिए एक घोषणा और परिभाषा के बीच अंतर को समझना महत्वपूर्ण है: एक परिभाषा नियम । C ++ मानक के खंड 3.2.1 से:

किसी भी अनुवाद इकाई में किसी भी चर, फ़ंक्शन, वर्ग प्रकार, गणना प्रकार या टेम्पलेट की एक से अधिक परिभाषा नहीं होगी।


"एक वर्ग परिभाषा के भीतर एक स्थिर सदस्य की घोषणा करता है" - यह सच है भले ही स्थैतिक सदस्य को आरंभीकृत किया गया हो, सही है? क्या हम उदाहरण बना सकते हैं struct x {static int b = 3; };?
RJFalconer

@RJFalconer आप सही हैं; आरंभीकरण आवश्यक रूप से एक घोषणा को परिभाषा में नहीं बदलता है (जो कि उम्मीद कर सकता है, इसके विपरीत; निश्चित रूप से मुझे यह आश्चर्यजनक लगा)। उदाहरण के लिए आपका संशोधन वास्तव में अवैध है जब तक bकि घोषित भी नहीं किया जाता है const। देखें stackoverflow.com/a/3536513/1858225 और daniweb.com/software-development/cpp/threads/140739/...
काइल स्ट्रैंड

1
यह मेरे लिए दिलचस्प है। आपके उत्तर के अनुसार, ऐसा लगता है कि सी ++ में, एक घोषणा भी एक परिभाषा है (अपवादों के साथ), जबकि सी मानक में यह अन्य दृष्टिकोण (C99, खंड 6.7, घोषणाओं) से प्रकाशित होता है: " एक पहचानकर्ता की परिभाषा उस पहचानकर्ता के लिए एक घोषणा: जो [विभिन्न मामलों के लिए मापदंड द्वारा पीछा किया जाता है] "। इसे देखने के विभिन्न तरीके, मुझे लगता है। :)
विक्टर ज़ामेनियन

संकलक एक नाम को स्वीकार करने के लिए संकलक के लिए है (संकलक को यह बताने के लिए कि नाम कानूनी है, नाम का परिचय इरादे से नहीं टाइपो से हुआ है)। परिभाषा वह जगह है जहां एक नाम और उसकी सामग्री जुड़ी हुई है। परिभाषा का उपयोग लिंकर द्वारा नाम की सामग्री के लिए एक नाम संदर्भ को जोड़ने के लिए किया जाता है।
गाब 45

137

घोषणा: "कहीं न कहीं, एक धूआं मौजूद है।"

परिभाषा: "... और यहाँ यह है!"


3
संकलक एक नाम को स्वीकार करने के लिए संकलक के लिए है (संकलक को यह बताने के लिए कि नाम कानूनी है, नाम इरादे के साथ पेश किया गया है न कि टाइपो)। परिभाषा वह जगह है जहां एक नाम और उसकी सामग्री जुड़ी हुई है। परिभाषा का उपयोग लिंकर द्वारा नाम की सामग्री के लिए एक नाम संदर्भ को जोड़ने के लिए किया जाता है।
गाब 41

46

C ++ में दिलचस्प एज केस हैं (उनमें से कुछ C में भी)। विचार करें

T t;

यह परिभाषा या एक घोषणा हो सकती है, जो इस बात पर निर्भर करता Tहै:

typedef void T();
T t; // declaration of function "t"

struct X { 
  T t; // declaration of function "t".
};

typedef int T;
T t; // definition of object "t".

C ++ में, टेम्प्लेट का उपयोग करते समय, एक और किनारे का मामला होता है।

template <typename T>
struct X { 
  static int member; // declaration
};

template<typename T>
int X<T>::member; // definition

template<>
int X<bool>::member; // declaration!

अंतिम घोषणा कोई परिभाषा नहीं थी । यह स्थैतिक सदस्य के एक स्पष्ट विशेषज्ञता की घोषणा है X<bool>। यह संकलक को बताता है: "अगर यह तात्कालिकता की बात आती है X<bool>::member, तो प्राथमिक टेम्पलेट से सदस्य की परिभाषा को तुरंत न करें, लेकिन कहीं और पाई गई परिभाषा का उपयोग करें"। इसे एक परिभाषा बनाने के लिए, आपको एक इनिलाइज़र की आपूर्ति करनी होगी

template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.

35

घोषणा

घोषणाएँ संकलक को बताती हैं कि प्रोग्राम तत्व या नाम मौजूद है। एक घोषणा एक कार्यक्रम में एक या एक से अधिक नामों का परिचय देती है। घोषणाएं एक कार्यक्रम में एक से अधिक बार हो सकती हैं। इसलिए, प्रत्येक संकलन इकाई के लिए कक्षाएं, संरचनाएं, प्रगणित प्रकार और अन्य उपयोगकर्ता-परिभाषित प्रकार घोषित किए जा सकते हैं।

परिभाषा

परिभाषाएँ निर्दिष्ट करती हैं कि नाम किस कोड या डेटा का वर्णन करता है। इसका उपयोग करने से पहले एक नाम घोषित किया जाना चाहिए।


उम, क्या यह नहीं है कि आप प्रत्येक संकलन इकाई में कक्षाएं और एनम को भी परिभाषित कर सकते हैं ? कम से कम मैंने कक्षा की परिभाषाएँ अपने हेडर में डालीं और उन्हें सभी में शामिल किया। एर, class foo {}; है एक वर्ग परिभाषा , हैं ना?
sbi

1
हाँ। हालाँकि, "क्लास फू;" एक घोषणा है। यह संकलक को बताता है कि फू एक वर्ग है। "कक्षा फू {};" एक परिभाषा है। यह कंपाइलर को बताता है कि किस तरह का क्लास फू है।
डेविड थोरले

1
अपवाद वर्ग के सदस्य नाम हैं जिनका उपयोग घोषित होने से पहले किया जा सकता है।
जोहान्स स्काउब -

1
हाँ, यही मेरा मतलब है। तो आप निम्न कार्य कर सकते हैं: संरचनात्मक फू {शून्य बी () {एफ (); } शून्य च (); }, f अभी तक घोषित नहीं होने के बावजूद दिखाई दे रहा है। निम्नलिखित कार्य भी: संरचना फू {शून्य बी (इंट = बार ()); typedef int बार; } ;. यह "सभी फ़ंक्शन निकायों, डिफ़ॉल्ट तर्क, निर्माता ctor-initializers" में इसकी घोषणा से पहले दिखाई देता है। वापसी के प्रकार में नहीं :(
जोहान्स स्काउब -

1
@ नोट: घोषणा से पहले यह दिखाई नहीं देता है, यह केवल यह है कि पहचानकर्ता का उपयोग घोषणा के पीछे ले जाया जाता है। हाँ, मुझे पता है, प्रभाव कई मामलों के लिए समान है। लेकिन सभी मामलों के लिए नहीं, यही कारण है कि मुझे लगता है कि हमें सटीक स्पष्टीकरण का उपयोग करना चाहिए। - उफ़, रुको। यह डिफ़ॉल्ट तर्कों में दिखाई देता है? खैर, यह निश्चित रूप से मेरी समझ से कहर ढाता है। Dammit! <pouts>
sbi

22

C99 मानक से, 6.7 (5):

एक घोषणा पहचानकर्ताओं के एक समूह की व्याख्या और विशेषताओं को निर्दिष्ट करती है। एक पहचानकर्ता की परिभाषा उस पहचानकर्ता के लिए एक घोषणा है:

  • किसी वस्तु के लिए, उस वस्तु के लिए भंडारण आरक्षित होने का कारण बनता है;
  • एक फ़ंक्शन के लिए, फ़ंक्शन बॉडी शामिल है;
  • एक निरंतर या टाइप किए गए नाम के लिए, पहचानकर्ता की (केवल) घोषणा है।

C ++ मानक से, 3.1 (2):

एक घोषणा एक परिभाषा है जब तक कि यह फ़ंक्शन के शरीर को निर्दिष्ट किए बिना एक फ़ंक्शन की घोषणा नहीं करता है, इसमें बाहरी विनिर्देशक या एक लिंकेज-विनिर्देश शामिल हैं और न ही एक इनिशियलाइज़र और न ही एक फ़ंक्शन-बॉडी, यह एक क्लास घोषणा में एक स्थिर डेटा सदस्य की घोषणा करता है, यह है वर्ग नाम की घोषणा, या यह एक टाइप-डी घोषणा, एक प्रयोग-घोषणा, या एक प्रयोग-निर्देश है।

फिर कुछ उदाहरण हैं।

तो दिलचस्प है (या नहीं, लेकिन मैं इससे थोड़ा आश्चर्यचकित हूं), typedef int myint;C99 में एक परिभाषा है, लेकिन केवल C ++ में एक घोषणा है।


@onebyone: के बारे में typedef, इसका मतलब यह नहीं होगा कि इसे C ++ में दोहराया जा सकता है, लेकिन C99 में नहीं?
भारतीय स्टेट बैंक

इसने मुझे चौंका दिया, और जहाँ तक एक अनुवाद इकाई का सवाल है, हाँ यह अंतर है। लेकिन स्पष्ट रूप से विभिन्न प्रकार की अनुवाद इकाइयों में C99 में एक टंकण को ​​दोहराया जा सकता है। C के पास C ++ की तरह स्पष्ट "एक परिभाषा नियम" नहीं है, इसलिए इसके पास जो नियम हैं वे इसे अनुमति देते हैं। C ++ ने इसे एक घोषणा में बदलने के लिए चुना, लेकिन एक परिभाषा नियम यह भी बताता है कि यह किस प्रकार की चीजों पर लागू होता है, और टाइपडेफ उनमें से एक नहीं है। इसलिए ODR के तहत C ++ में दोहराए जाने की अनुमति दी जाएगी क्योंकि यह शब्द है, भले ही एक टाइपीडिफ एक परिभाषा हो। अनावश्यक रूप से अचार लगता है।
स्टीव जेसोप

... लेकिन मुझे लगता है कि ODR में वह सूची वास्तव में उन सभी चीजों को सूचीबद्ध करती है जिनकी परिभाषाएँ संभव हैं। यदि ऐसा है, तो सूची वास्तव में बेमानी है, और बस मददगार होने के लिए है।
स्टीव जेसोप

कक्षा की परिभाषा के बारे में एसटीडी की ओडीआर परिभाषा क्या कहती है? वे है दोहराया जाना।
sbi

2
@sbi: ODR का कहना है "(1) किसी भी अनुवाद इकाई में किसी भी प्रकार की एक से अधिक परिभाषा नहीं होगी ... वर्ग प्रकार" और "(5) एक वर्ग प्रकार की एक से अधिक परिभाषा हो सकती है ... एक कार्यक्रम में जो प्रदान की गई है प्रत्येक परिभाषा एक अलग अनुवाद इकाई में दिखाई देती है "और फिर कुछ अतिरिक्त आवश्यकताएं जो" परिभाषाएं समान हैं "।
स्टीव जेसप

17

Wiki.answers.com से:

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

उदाहरण के लिए, निम्नलिखित सभी घोषणाएँ हैं:

extern int a; 
struct _tagExample { int a; int b; }; 
int myFunc (int a, int b);

दूसरी ओर परिभाषा का अर्थ है कि घोषणा करने के लिए सभी चीजों के अतिरिक्त, स्मृति में स्थान भी आरक्षित है। आप कह सकते हैं "परिभाषा = घोषणा + अंतरिक्ष आरक्षण" निम्नलिखित परिभाषा के उदाहरण हैं:

int a; 
int b = 0; 
int myFunc (int a, int b) { return a + b; } 
struct _tagExample example; 

उत्तर देखें ।


3
यह भी, गलत है (हालांकि दूसरों की तुलना में बहुत करीब): struct foo {};एक परिभाषा है , एक घोषणा नहीं। की घोषणा fooहोगी struct foo;। उस से, संकलक को पता नहीं है कि fooवस्तुओं के लिए कितना स्थान आरक्षित करना है।
sbi

1
@ मरीन: sbi कह रहा है कि "कंपाइलर जानता है कि इस प्रकार का एक वैरिएबल निर्मित होने पर कितना स्थान आरक्षित करना है" हमेशा सच नहीं होता है। struct foo;एक घोषणा है, लेकिन यह संकलक को फू के आकार को नहीं बताता है। मैं जोड़ना चाहता हूँ कि struct _tagExample { int a; int b; };एक परिभाषा है। इसलिए इस संदर्भ में इसे एक घोषणा कहा जाना भ्रामक है। बेशक यह एक है, चूंकि सभी परिभाषाएं घोषणाएं हैं, लेकिन आप यह सुझाव देते हैं कि यह एक परिभाषा नहीं है। यह एक परिभाषा है, _tagExample की।
स्टीव जेसप

1
@ मारिन गिल: जिसका अर्थ है कि "उत्तर" विकी हमेशा सटीक नहीं होता है। मुझे यहाँ गलत जानकारी के लिए नीचा दिखाना होगा।
डेविड थॉर्नले

1
हम सीखते हैं कि क्या कहा गया है, यह सच है लेकिन (IMO) वास्तव में इस सवाल का जवाब नहीं देता है। मार्सिन ने जो कहा वह झूठा है। मानकों का हवाला देना सही है और सवाल का जवाब देता है, लेकिन सिर या पूंछ बनाना बहुत मुश्किल है।
स्टीव जेसोप

1
@ डेविड थॉर्नले - कोई समस्या नहीं :) यह वही है जो इस साइट के बारे में है। हम जानकारी का चयन और सत्यापन करते हैं।
Marcin Gil

13

C ++ 11 अद्यतन

चूँकि मुझे C ++ 11 का उत्तर यहाँ पर नहीं मिला है।

घोषणापत्र एक परिभाषा है जब तक कि यह / n घोषित नहीं करता है:

  • अपारदर्शी एनम - enum X : int;
  • टेम्पलेट पैरामीटर - T मेंtemplate<typename T> class MyArray;
  • पैरामीटर घोषणा - x और y इनint add(int x, int y);
  • अन्य घोषणा - using IntVector = std::vector<int>;
  • स्थिर मुखर घोषणा - static_assert(sizeof(int) == 4, "Yikes!")
  • विशेषता घोषणा (कार्यान्वयन-परिभाषित)
  • खाली घोषणा ;

उपरोक्त सूची द्वारा C ++ 03 से विरासत में प्राप्त अतिरिक्त खंड:

  • समारोह घोषणा - जोड़ें मेंint add(int x, int y);
  • एक्सटर्नल स्पेसिफ़ायर जिसमें डिक्लेरेशन या लिंकेज स्पेसियर होता है - extern int a; याextern "C" { ... };
  • एक वर्ग में स्थैतिक डेटा सदस्य - x मेंclass C { static int x; };
  • वर्ग / संरचना घोषणा - struct Point;
  • टंकण की घोषणा - typedef int Int;
  • घोषणा का उपयोग कर - using std::cout;
  • निर्देश का उपयोग - using namespace NS;

एक टेम्पलेट-घोषणा एक घोषणा है। टेम्प्लेट-घोषणा भी एक परिभाषा है यदि इसकी घोषणा एक फ़ंक्शन, एक वर्ग या एक स्थिर डेटा सदस्य को परिभाषित करती है।

उस मानक से उदाहरण जो घोषणा और परिभाषा के बीच अंतर करता है जो मुझे उनके बीच की बारीकियों को समझने में मददगार मिला:

// except one all these are definitions
int a;                                  // defines a
extern const int c = 1;                 // defines c
int f(int x) { return x + a; }          // defines f and defines x
struct S { int a; int b; };             // defines S, S::a, and S::b
struct X {                              // defines X
    int x;                              // defines non-static data member x
    static int y;                       // DECLARES static data member y
    X(): x(0) { }                       // defines a constructor of X
};
int X::y = 1;                           // defines X::y
enum { up , down };                     // defines up and down
namespace N { int d; }                  // defines N and N::d
namespace N1 = N;                       // defines N1
X anX;                                  // defines anX


// all these are declarations
extern int a;                           // declares a
extern const int c;                     // declares c
int f(int);                             // declares f
struct S;                               // declares S
typedef int Int;                        // declares Int
extern X anotherX;                      // declares anotherX
using N::d;                             // declares N::d


// specific to C++11 - these are not from the standard
enum X : int;                           // declares X with int as the underlying type
using IntVector = std::vector<int>;     // declares IntVector as an alias to std::vector<int>
static_assert(X::y == 1, "Oops!");      // declares a static_assert which can render the program ill-formed or have no effect like an empty declaration, depending on the result of expr
template <class T> class C;             // declares template class C
;                                       // declares nothing

6

परिभाषा:

extern int a;      // Declaration 
int a;             // Definition
a = 10             // Initialization
int b = 10;        // Definition & Initialization

परिभाषा चर को एक प्रकार के साथ जोड़ती है और स्मृति को आवंटित करती है, जबकि घोषणा केवल प्रकार को निर्दिष्ट करती है लेकिन स्मृति को आवंटित नहीं करती है। जब आप परिभाषा से पहले चर को संदर्भित करना चाहते हैं तो घोषणा अधिक उपयोगी है।

* आरंभ के साथ परिभाषा को भ्रमित न करें। दोनों अलग-अलग हैं, प्रारंभिक चर के लिए मूल्य देता है। उपरोक्त उदाहरण देखें।

निम्नलिखित परिभाषा के कुछ उदाहरण हैं।

int a;
float b;
double c;

अब कार्य घोषणा:

int fun(int a,int b); 

फ़ंक्शन के अंत में अर्धविराम पर ध्यान दें तो यह कहता है कि यह केवल एक घोषणा है। कंपाइलर जानता है कि कहीं उस प्रोग्राम में उस प्रोटोटाइप के साथ फ़ंक्शन को परिभाषित किया जाएगा । अब यदि कंपाइलर को फंक्शन कॉल कुछ इस तरह से मिलता है

int b=fun(x,y,z);

कंपाइलर एक त्रुटि यह कहते हुए फेंक देगा कि ऐसा कोई फ़ंक्शन नहीं है। क्योंकि इसमें उस फ़ंक्शन के लिए कोई प्रोटोटाइप नहीं है।

दो कार्यक्रमों के बीच अंतर पर ध्यान दें।

कार्यक्रम 1

#include <stdio.h>
void print(int a)
{
     printf("%d",a);
}
main()
{
    print(5);
}

इसमें प्रिंट फंक्शन को घोषित और परिभाषित किया जाता है। चूंकि फंक्शन कॉल परिभाषा के बाद आ रहा है। अब अगला कार्यक्रम देखें।

कार्यक्रम 2

 #include <stdio.h>
 void print(int a); // In this case this is essential
 main()
 {
    print(5);
 }
 void print(int a)
 {
     printf("%d",a);
 }

यह आवश्यक है क्योंकि फंक्शन कॉल प्रीसिड डेफिनेशन है इसलिए कंपाइलर को पता होना चाहिए कि क्या कोई ऐसा फंक्शन है। इसलिए हम फ़ंक्शन की घोषणा करते हैं जो संकलक को सूचित करेगा।

परिभाषा:

किसी फ़ंक्शन को परिभाषित करने के इस भाग को परिभाषा कहा जाता है। यह कहता है कि फ़ंक्शन के अंदर क्या करना है।

void print(int a)
{
    printf("%d",a);
}

2
int a; //declaration; a=10; //definitionयह पूरी तरह से गलत है। जब स्वचालित भंडारण अवधि ऑब्जेक्ट्स के बारे में बात की जाती है (ऑब्जेक्ट एक फ़ंक्शन परिभाषा के अंदर घोषित किए जाते हैं जो किसी अन्य स्टोरेज क्लास स्पेसर जैसे एक्सटर्नल के साथ घोषित नहीं होते हैं) तो ये हमेशा परिभाषाएं होती हैं।
जॉय पाबलिनस

समझ के लिए मुख्य अंतर यह है कि एक घोषणा कह रही है "एक चीज़ कहीं मौजूद है जिसमें ये लक्षण (प्रकार आदि) हैं," जबकि एक परिभाषा कह रही है "मैं इन लक्षणों के साथ एक चीज़ की घोषणा कर रहा हूं, और मैं इसे यहां भी बता रहा हूं। कुंआ।" चूंकि आप इस तरह से स्वचालित भंडारण अवधि की वस्तुओं को घोषित नहीं कर सकते हैं, वे हमेशा परिभाषा होंगे।
जॉय पाबलिनस

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

अपनी पहली टिप्पणी के अनुसार उत्तर को अपडेट करें। हालाँकि, मैं इस टिप्पणी से सहमत नहीं हूँ "जब आप किसी चीज़ को तुरंत कर रहे होते हैं, तो आपको कंपाइलर को यह भी बताना होगा कि वह चीज़ मौजूद है"। हम हमेशा तुरंत टाइप करते समय lhs के प्रकार को निर्दिष्ट नहीं करते। Ex: a = 10 हम यहां किसी भी "लक्षण" को निर्दिष्ट नहीं कर रहे हैं।
श्रीधरन

4

परिभाषा का अर्थ है वास्तविक कार्य लिखित और घोषणा का अर्थ है उदाहरण के लिए सरल घोषणा कार्य

void  myfunction(); //this is simple declaration

तथा

void myfunction()
{
 some statement;    
}

यह फ़ंक्शन myfunction की परिभाषा है


1
और प्रकार और वस्तुओं के बारे में क्या?
sbi

4

अंगूठे का नियम:

  • एक घोषणा संकलक को बताती है कि चर के डेटा को मेमोरी में कैसे व्याख्या करें। यह हर पहुंच के लिए आवश्यक है।

  • एक परिभाषा चर को मौजूदा बनाने के लिए मेमोरी को सुरक्षित रखती है। यह पहली पहुंच से ठीक पहले एक बार होना है।


2
यह केवल वस्तुओं के लिए धारण करता है। प्रकार और कार्यों के बारे में क्या?
in पर ऑर्बिट

4

संज्ञाओं को समझने के लिए, पहले क्रियाओं पर ध्यान दें।

घोषणा करना - आधिकारिक तौर पर घोषणा करना; प्रोक्लेम

परिभाषित करना - स्पष्ट रूप से और पूरी तरह से (किसी या कुछ) को दिखाने या वर्णन करने के लिए

इसलिए, जब आप कुछ घोषित करते हैं, तो आप यह बताते हैं कि यह क्या है

// declaration
int sum(int, int);

यह रेखा एक C फ़ंक्शन को घोषित करती है जिसे sumटाइप के दो तर्क लगते हैं intऔर रिटर्न देता है int। हालाँकि, आप अभी तक इसका उपयोग नहीं कर सकते।

जब आप प्रदान करते हैं कि यह वास्तव में कैसे काम करता है , तो इसकी परिभाषा है।

// definition
int sum(int x, int y)
{
    return x + y;
}

3

घोषणा और परिभाषा के बीच अंतर को समझने के लिए हमें विधानसभा कोड देखने की जरूरत है:

uint8_t   ui8 = 5;  |   movb    $0x5,-0x45(%rbp)
int         i = 5;  |   movl    $0x5,-0x3c(%rbp)
uint32_t ui32 = 5;  |   movl    $0x5,-0x38(%rbp)
uint64_t ui64 = 5;  |   movq    $0x5,-0x10(%rbp)
double   doub = 5;  |   movsd   0x328(%rip),%xmm0        # 0x400a20
                        movsd   %xmm0,-0x8(%rbp)

और यह केवल परिभाषा है:

ui8 = 5;   |   movb    $0x5,-0x45(%rbp)
i = 5;     |   movl    $0x5,-0x3c(%rbp)
ui32 = 5;  |   movl    $0x5,-0x38(%rbp)
ui64 = 5;  |   movq    $0x5,-0x10(%rbp)
doub = 5;  |   movsd   0x328(%rip),%xmm0        # 0x400a20
               movsd   %xmm0,-0x8(%rbp)

जैसा कि आप कुछ भी नहीं बदल सकते देख सकते हैं।

घोषणा परिभाषा से अलग है क्योंकि यह केवल संकलक द्वारा उपयोग की गई जानकारी देती है। उदाहरण के लिए uint8_t संकलक को एएसएम फ़ंक्शन का उपयोग करने के लिए कहें।

देखना है कि:

uint def;                  |  no instructions
printf("some stuff...");   |  [...] callq   0x400450 <printf@plt>
def=5;                     |  movb    $0x5,-0x45(%rbp)

घोषणा एक बराबर निर्देश नहीं है क्योंकि यह निष्पादित होने वाली कोई चीज नहीं है।

इसके अलावा घोषणा संकलक को चर का दायरा बताती है।

हम कह सकते हैं कि घोषणा कंपाइलर द्वारा चर के सही उपयोग को स्थापित करने के लिए और कुछ मेमोरी के कुछ चर के लिए कितनी देर के लिए उपयोग की जाने वाली जानकारी है।


2

आप सबसे सामान्य शब्दों में संभव नहीं बता सकते, कि एक घोषणा एक पहचानकर्ता है जिसमें कोई भंडारण आवंटित नहीं किया जाता है और एक परिभाषा वास्तव में एक घोषित पहचानकर्ता से भंडारण आवंटित करती है?

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


1
आपकी परिभाषा गलत नहीं है, लेकिन जब कार्य परिभाषाएँ आती हैं, तो "संग्रहण परिभाषा" हमेशा अजीब लगती है। टेम्प्लेट के बारे में: यह template<class T> struct foo;एक टेम्प्लेट घोषणा है , और ऐसा ही है template<class T> void f();। टेम्प्लेट परिभाषाएँ मिरर क्लास / फ़ंक्शन परिभाषाएँ उसी तरह से। (ध्यान दें कि एक टेम्पलेट नाम एक प्रकार या फ़ंक्शन नाम नहीं है । एक जगह जहां आप यह देख सकते हैं, जब आप एक टेम्पलेट को किसी अन्य टेम्पलेट के प्रकार पैरामीटर के रूप में पारित नहीं कर सकते। यदि आप प्रकारों के बजाय टेम्पलेट पास करना चाहते हैं, तो आपको टेम्पलेट टेम्पलेट मापदंडों की आवश्यकता है। )
sbi

सहमत हैं कि 'भंडारण परिभाषा' अजीब है, विशेष रूप से फ़ंक्शन परिभाषाओं के बारे में। घोषणा int foo () है और परिभाषा int foo () {// कुछ कोड यहाँ ..} है। मुझे आमतौर पर अपने छोटे मस्तिष्क को अवधारणाओं के साथ लपेटने की आवश्यकता होती है

2

इसी तरह उत्तर यहां देखें: तकनीकी साक्षात्कार सी में प्रश्न

एक घोषणा कार्यक्रम को एक नाम प्रदान करती है; एक परिभाषा कार्यक्रम के भीतर एक इकाई (जैसे प्रकार, उदाहरण और कार्य) का एक अनूठा विवरण प्रदान करती है। घोषणाओं को एक दिए गए दायरे में दोहराया जा सकता है, यह एक दिए गए दायरे में एक नाम का परिचय देता है।

एक घोषणा एक परिभाषा है जब तक कि:

  • घोषणा अपने शरीर को निर्दिष्ट किए बिना एक समारोह की घोषणा करती है,
  • घोषणा में एक बाह्य विनिर्देशक होता है और कोई आरम्भक या कार्य निकाय नहीं होता है,
  • घोषणा एक वर्ग परिभाषा के बिना एक स्थिर वर्ग डेटा सदस्य की घोषणा है,
  • घोषणा एक वर्ग का नाम है,

जब तक एक परिभाषा एक घोषणा है:

  • परिभाषा एक स्थिर वर्ग डेटा सदस्य को परिभाषित करती है,
  • परिभाषा एक गैर-इनलाइन सदस्य फ़ंक्शन को परिभाषित करती है।

1

यह वास्तव में बहुत अच्छा लग रहा है, लेकिन यह सबसे अच्छा तरीका है जिससे मैं अपने सिर को सीधा रख सकूंगा:

घोषणा: चित्र थॉमस जेफरसन एक भाषण दे रहा है ... "मैं इस जगह में इस तरह से निर्णय लेता हूँ !!!"

परिभाषा: एक शब्दकोश तस्वीर, आप फू देख रहे हैं और इसका वास्तव में क्या मतलब है।


1

एक घोषणा संकलक को एक प्रतीक नाम प्रस्तुत करती है। एक परिभाषा एक घोषणा है जो प्रतीक के लिए स्थान आवंटित करती है।

int f(int x); // function declaration (I know f exists)

int f(int x) { return 2*x; } // declaration and definition

1

GNU C लाइब्रेरी मैनुअल के अनुसार ( http://www.gnu.org/software/libc/manual/html_node/Header-Files.html )

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


0

डिक्लेरेशन और डेफिनिशन की अवधारणा एक ऐसी स्थिति बन जाएगी जब आप बाहरी स्टोरेज क्लास का उपयोग कर रहे होंगे क्योंकि आपकी परिभाषा किसी अन्य स्थान पर होगी और आप अपनी स्थानीय कोड फ़ाइल (पेज) में चर घोषित कर रहे हैं। C और C ++ के बीच एक अंतर यह है कि C में आप फ़ंक्शन या कोड पेज की शुरुआत में सामान्य रूप से घोषणाएं करते हैं। C ++ में ऐसा नहीं है। आप अपनी पसंद की जगह पर घोषित कर सकते हैं।


1
यह परिभाषा के साथ घोषणा को भ्रमित करता है और सादा गलत है।
sbi

0

मेरा पसंदीदा उदाहरण "int Num = 5" है यहां आपका वैरिएबल 1. int के रूप में परिभाषित किया गया है। Num के रूप में घोषित किया गया है और 3. पाँच के मान के साथ तुरंत। हम

  • एक वस्तु के प्रकार को परिभाषित करें, जो अंतर्निहित या एक वर्ग या संरचना हो सकती है।
  • किसी वस्तु के नाम की घोषणा करें, इसलिए एक नाम के साथ कुछ भी घोषित किया गया है जिसमें चर, फंटियन आदि शामिल हैं।

एक वर्ग या संरचना आपको यह बदलने की अनुमति देती है कि बाद में उपयोग किए जाने पर वस्तुओं को कैसे परिभाषित किया जाएगा। उदाहरण के लिए

  • कोई एक विषम चर या सरणी घोषित कर सकता है जो विशेष रूप से परिभाषित नहीं हैं।
  • C ++ में एक ऑफसेट का उपयोग करके आप एक ऑब्जेक्ट को परिभाषित कर सकते हैं जिसमें एक घोषित नाम नहीं है।

जब हम प्रोग्रामिंग सीखते हैं तो इन दोनों शब्दों को अक्सर भ्रमित किया जाता है क्योंकि हम अक्सर एक ही समय में दोनों करते हैं।


मुझे समझ नहीं आता कि इतने लोगों ने sbi के जवाब को क्यों गलत ठहराया। मैंने bhhend द्वारा उत्तर को अपवित्र किया, जो कि मेरी तुलना में काफी अच्छा, संक्षिप्त, सटीक और बहुत अधिक सामयिक था। मुझे यह देखकर दुख हुआ कि मैं 4 साल में ऐसा करने वाला पहला व्यक्ति था।
जेसन के।

0

एक निष्पादन योग्य पीढ़ी के चरण:

(1) प्री-प्रोसेसर -> (2) अनुवादक / संकलक -> (3) लिंकर

चरण 2 (अनुवादक / संकलक) में, हमारे कोड में घोषित बयान संकलक को बताते हैं कि ये चीजें जिनका हम भविष्य में उपयोग करने जा रहे हैं और आप बाद में परिभाषा पा सकते हैं, जिसका अर्थ है:

अनुवादक सुनिश्चित करें कि: क्या है? घोषणा का मतलब है

और (3) चरण (लिंकर) को चीजों को बांधने के लिए परिभाषा की आवश्यकता है

लिंकर सुनिश्चित करें कि: क्या है? मतलब परिभाषा


0

के एंड आर (2 डी संस्करण) में छिड़के गए कुछ बहुत स्पष्ट परिभाषाएं हैं; यह उन्हें एक स्थान पर रखने और उन्हें एक के रूप में पढ़ने में मदद करता है:

"परिभाषा" उस जगह को संदर्भित करता है जहां चर बनाया या सौंपा गया भंडारण है; "घोषणा" उन स्थानों को संदर्भित करता है जहां चर की प्रकृति बताई गई है लेकिन कोई भंडारण आवंटित नहीं किया गया है। [पी। 33]

...

बाहरी चर की घोषणा और इसकी परिभाषा के बीच अंतर करना महत्वपूर्ण है । एक घोषणा एक चर के गुणों की घोषणा करती है (मुख्य रूप से इसका प्रकार); एक परिभाषा के कारण भंडारण भी अलग सेट हो जाता है। अगर रेखाएं

int sp;
double val[MAXVAL]

किसी भी फ़ंक्शन के बाहर दिखाई देते हैं, वे बाहरी चर को परिभाषित करते हैं spऔर val, भंडारण को अलग सेट करने का कारण बनते हैं, और शेष स्रोत फ़ाइल के लिए घोषणा के रूप में भी काम करते हैं।

दूसरी ओर, लाइनें

extern int sp;
extern double val[];

बाकी स्रोत फ़ाइल के लिए घोषित करें जो spएक है intऔर वह valएक doubleसरणी है (जिसका आकार कहीं और निर्धारित किया गया है), लेकिन वे उनके लिए चर या आरक्षित भंडारण नहीं बनाते हैं।

स्रोत प्रोग्राम बनाने वाली सभी फ़ाइलों के बीच एक बाहरी चर की केवल एक परिभाषा होनी चाहिए । ... ऐरे आकार को परिभाषा के साथ निर्दिष्ट किया जाना चाहिए, लेकिन एक externघोषणा के साथ वैकल्पिक हैं । [पीपी। 80-81]

...

घोषणाएँ प्रत्येक पहचानकर्ता को दी गई व्याख्या को निर्दिष्ट करती हैं; वे आवश्यक रूप से पहचानकर्ता के साथ जुड़े भंडारण को आरक्षित नहीं करते हैं। घोषणाएँ कि आरक्षित भंडारण को परिभाषाएँ कहा जाता है । [पी। 210]


-1

घोषणा का अर्थ है, चर को नाम और प्रकार दें (चर घोषणा के मामले में), जैसे:

int i;

या नाम, वापसी प्रकार और पैरामीटर (ओं) प्रकार शरीर के बिना एक समारोह के लिए (फ़ंक्शन घोषणा के मामले में), जैसे:

int max(int, int);

जबकि परिभाषा का अर्थ है किसी चर के लिए मान निर्दिष्ट करना (चर परिभाषा के मामले में), उदाहरण के लिए:

i = 20;

या किसी फंक्शन में बॉडी (कार्यक्षमता) प्रदान / जोड़ना फंक्शन डेफिनिशन कहलाता है, जैसे:

int max(int a, int b)
{
   if(a>b)   return a;
   return b;  
}

कई बार घोषणा और परिभाषा को एक साथ किया जा सकता है:

int i=20;

तथा:

int max(int a, int b)
{
    if(a>b)   return a;
    return b;    
} 

उपरोक्त मामलों में हम परिवर्तनशील iऔर घोषित करते हैं और function max()


परिभाषा का वास्तविक अर्थ यदि वैरिएबल / फंक्शन में वैल्यू / बॉडी असाइन करना है जबकि डिक्लेरेशन का अर्थ है नाम प्रदान करना, एक वेरिएबल / फंक्शन टाइप करें
पुनीत पुरोहित

आप किसी मान को बताए बिना उसे परिभाषित कर सकते हैं।
कक्षा


वेरिएबल x का डिक्लेरेशन इसका डिफिनेशन नहीं
पुनीत पुरोहित

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