हेडर में एक संरचना की घोषणा कैसे करें जो कि सी में कई फ़ाइलों द्वारा उपयोग की जानी है?


115

अगर मेरे पास एक स्ट्रक्च वाली source.c फाइल है:

struct a { 
    int i;
    struct b {
        int j;
    }
};

किसी अन्य फ़ाइल (यानी func.c) में इस संरचना का उपयोग कैसे किया जा सकता है ?

क्या मुझे एक नई हेडर फ़ाइल बनानी चाहिए, वहाँ संरचना की घोषणा करें और उस हेडर को इसमें शामिल करें func.c?

या क्या मुझे हेडर फ़ाइल में पूरी संरचना को परिभाषित करना चाहिए और इसमें source.cऔर दोनों में शामिल होना चाहिए func.c? externदोनों फाइलों में संरचना कैसे घोषित की जा सकती है ?

क्या मुझे typedefऐसा करना चाहिए ? यदि हां, तो कैसे?


ध्यान दें कि संरचना की परिभाषा मान्य नहीं है। सी। के लिए कम से कम ब्रेस के बाद एक अर्धविराम होना चाहिए struct b, लेकिन तब आपकी संरचना aएक प्रकार की घोषणा करती है जो अप्रयुक्त है (आपको शायद kआंतरिक नाम के ब्रेस के बाद एक सदस्य का नाम परिभाषित करना चाहिए। अर्धविराम से पहले।
जोनाथन लेफ़लर 23

जवाबों:


140

अगर इस संरचना को किसी अन्य फ़ाइल func.c द्वारा उपयोग किया जाना है तो इसे कैसे करें?

जब किसी फ़ाइल (यानी func.c फ़ाइल) में एक प्रकार का उपयोग किया जाता है, तो इसे दिखाई देना चाहिए। यह करने के लिए सबसे खराब तरीका यह है कि प्रत्येक स्रोत फ़ाइल में इसे कॉपी पेस्ट करना चाहिए।

सही तरीके से इसे हेडर फ़ाइल में रखा जा रहा है, और जब भी ज़रूरत हो इस हेडर फ़ाइल को शामिल करें।

क्या हम एक नई हेडर फ़ाइल खोलेंगे और वहाँ संरचना की घोषणा करेंगे और उस हेडर को func.c में शामिल करेंगे?

यह वह समाधान है जो मुझे अधिक पसंद है, क्योंकि यह कोड को अत्यधिक मॉड्यूलर बनाता है। मैं आपकी संरचना को इस प्रकार कोडित करूंगा:

#ifndef SOME_HEADER_GUARD_WITH_UNIQUE_NAME
#define SOME_HEADER_GUARD_WITH_UNIQUE_NAME

struct a
{ 
    int i;
    struct b
    {
        int j;
    }
};

#endif

मैं इस संरचना का उपयोग उसी हेडर (फ़ंक्शन जो "शब्दार्थ" इसके "इंटरफ़ेस" का हिस्सा हैं) में कर सकता हूं।

और आमतौर पर, मैं संरचना के नाम के बाद फाइल को नाम दे सकता हूं, और हेडर गार्ड को परिभाषित करने के लिए उस नाम का फिर से उपयोग कर सकता हूं।

यदि आपको संरचना के लिए एक सूचक का उपयोग करके एक फ़ंक्शन घोषित करने की आवश्यकता है, तो आपको पूर्ण संरचना परिभाषा की आवश्यकता नहीं होगी। एक सरल आगे की घोषणा की तरह:

struct a ;

पर्याप्त होगा, और यह युग्मन घटता है।

या हम हेडर फ़ाइल में कुल संरचना को परिभाषित कर सकते हैं और इसमें स्रोत और func.c दोनों को शामिल कर सकते हैं?

यह एक और तरीका है, कुछ हद तक आसान, लेकिन कम मॉड्यूलर: कुछ कोड को काम करने के लिए केवल आपकी संरचना की आवश्यकता होती है फिर भी सभी प्रकारों को शामिल करना होगा।

C ++ में, यह दिलचस्प जटिलता पैदा कर सकता है, लेकिन यह विषय से बाहर है (कोई C ++ टैग नहीं), इसलिए मैं विस्तृत नहीं करूंगा।

फिर दोनों फाइलों में उस संरचना को बाहरी घोषित कैसे करें। ?

मैं इस बिंदु को देखने में विफल रहता हूं, शायद, लेकिन ग्रेग हेवगिल ने अपनी पोस्ट में बहुत अच्छा उत्तर दिया है कि हेडर में एक संरचना कैसे घोषित की जाए जो कि सी में कई फ़ाइलों द्वारा उपयोग की जाए?

क्या हम इसे टाइप करेंगे, फिर कैसे?

  • यदि आप C ++ का उपयोग कर रहे हैं, तो नहीं।
  • यदि आप C का उपयोग कर रहे हैं, तो आपको करना चाहिए।

इसका कारण यह है कि C संरचना प्रबंधन एक दर्द हो सकता है: आपको हर जगह उपयोग किए जाने वाले संरचनात्मक कीवर्ड को घोषित करना होगा:

struct MyStruct ; /* Forward declaration */

struct MyStruct
{
   /* etc. */
} ;

void doSomething(struct MyStruct * p) /* parameter */
{
   struct MyStruct a ; /* variable */
   /* etc */
}

जबकि एक टाइप्डिफ आपको बिना संरचना कीवर्ड के इसे लिखने में सक्षम करेगा।

struct MyStructTag ; /* Forward declaration */

typedef struct MyStructTag
{
   /* etc. */
} MyStruct ;

void doSomething(MyStruct * p) /* parameter */
{
   MyStruct a ; /* variable */
   /* etc */
}

यह महत्वपूर्ण है कि आप अभी भी संरचना के लिए एक नाम रखें। लिख रहे हैं:

typedef struct
{
   /* etc. */
} MyStruct ;

केवल एक टाइप-सी-एड नाम के साथ एक अनाम संरचना बनाएगा, और आप इसे अग्रेषित-घोषित करने में सक्षम नहीं होंगे। तो निम्न प्रारूप में रखें:

typedef struct MyStructTag
{
   /* etc. */
} MyStruct ;

इस प्रकार, आप हर जगह MyStruct का उपयोग करने में सक्षम हो सकते हैं, जिसमें आप संरचनात्मक कीवर्ड जोड़ने से बचना चाहते हैं, और तब भी MyStructTag का उपयोग करें जब एक टाइपराइफ़ काम नहीं करेगा (अर्थात आगे की घोषणा)

संपादित करें:

सही ढंग से योनातान लेफ़लर द्वारा टिप्पणी के रूप में, C99 संरचना घोषणा के बारे में गलत धारणा ।

2018-06-01 संपादित करें:

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

वास्तव में, उपरोक्त कोड को इस प्रकार लिखा जा सकता है:

typedef struct MyStruct
{
   /* etc. */
} MyStruct ;

IIRC, यह वास्तव में वही है जो C ++ पर्दे के पीछे अपनी सरल संरचना की घोषणा के साथ करता है, इसे C के साथ संगत रखने के लिए:

// C++ explicit declaration by the user
struct MyStruct
{
   /* etc. */
} ;
// C++ standard then implicitly adds the following line
typedef MyStruct MyStruct;

वापस C पर, मैंने दोनों usages (अलग-अलग नाम और एक ही नाम) देखे हैं, और किसी को भी मेरे बारे में कमियां नहीं हैं, इसलिए समान नाम का उपयोग करने से रीडिंग सरल हो जाती है यदि आप स्ट्रक्सेस और अन्य प्रतीकों के लिए C अलग "नेमस्पेस" का उपयोग नहीं करते हैं ।


2
क्या आप टिप्पणी कर सकते हैं, या C99 मानक के खंड को इंगित कर सकते हैं जो आपके "यदि आप C99 का उपयोग कर रहे हैं, तो टिप्पणी नहीं"?
जोनाथन लेफ्लर 7

आप सही हे। मैंने हाल ही में एक C99 का परीक्षण किया और यह देखकर आश्चर्यचकित रह गया कि C ++ के तरीके का उपयोग करने पर मेरी अपरिभाषित संरचना को मान्यता नहीं दी गई थी। मैंने कंपाइलर विकल्पों की तलाश की, और फिर, सभी मानक दस्तावेजों में मैंने अपने हाथों को डाल दिया, लेकिन ऐसा कुछ भी नहीं मिला जो यह समझा सके कि मुझे यह संभव लगता है ...
20

2
... तो वैसे भी, टिप्पणी के लिए धन्यवाद। मैंने इसे अभी ठीक किया है।
पियरसेबल

structटैग और नाम के लिए अलग-अलग नामों का उपयोग करने की कोई आवश्यकता नहीं है typedef। C structटैग्स के लिए एक अलग नामस्थान का उपयोग करता है , इसलिए आप MyStructदोनों के लिए उपयोग कर सकते हैं ।
क्रेग बार्न्स

1
@CraigBarnes आप सही हैं, लेकिन मैं चाहता था कि कोड को पढ़कर ही स्पष्ट हो। अगर मैंने एक ही नाम दिया होता, तो यह सी "" एक ही घोषणा में "दो बार" नाम लिखने की आवश्यकता पर सी न्यूबीज़ को भ्रमित कर सकता था। मैं आपकी टिप्पणी का उल्लेख करते हुए एक नोट
जोड़ूंगा

34

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

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

extern struct a myAValue;

फिर, एक स्रोत फ़ाइल में, वास्तविक चर को परिभाषित करें:

struct a myAValue;

यदि आप ऐसा करना भूल जाते हैं या गलती से इसे दो स्रोत फ़ाइलों में परिभाषित करते हैं, तो लिंकर आपको इस बारे में बता देगा।


आपको एक लिंकर त्रुटि मिल सकती है, या आप नहीं कर सकते। सी में, लिंकेज मॉडल 'सामान्य' परिभाषाओं के लिए अनुमति देता है, इसलिए बिना किसी आरम्भिक (और शायद एक ही आरंभक के साथ) के साथ कई परिभाषाएँ काम कर सकती हैं। यह एक 'सामान्य विस्तार' है। कुछ संकलक अस्थायी (गायब) परिभाषाओं का भी समर्थन करते हैं, मेरा मानना ​​है।
जोनाथन लेफ़लर

फिर, एक स्रोत फ़ाइल में, वास्तविक चर को परिभाषित करें:; ... या गलती से इसे दो स्रोत फ़ाइलों में परिभाषित किया गया ... :)
जोहान्स शाउब -

घोषित / परिभाषित मुद्दे के लिए मैंने जो एक तकनीक का उपयोग किया है वह हैडर के शीर्ष पर सशर्त GLOBALरूप से externया कुछ भी नहीं के रूप में परिभाषित करना है और फिर चर के रूप में घोषित करना है GLOBAL struct a myAValue;। अधिकांश स्रोत फ़ाइलों से, आप #define GLOBAL externउपयोग किए जाने वाले संस्करण की व्यवस्था करते हैं ( चर घोषित करते हैं) और ठीक एक स्रोत फ़ाइल से यह खाली परिभाषित उपयोग करने का कारण बनता है इसलिए चर परिभाषित किए जाते हैं ।
ट्रिपहाउंड

आपके पास संरचना का नाम C में टाइप किए गए नाम के समान हो सकता है, लेकिन C ++ में नहीं।
xuhdev

6

आह:

#ifndef A_H
#define A_H

struct a { 
    int i;
    struct b {
        int j;
    }
};

#endif

आप वहां जाते हैं, अब आपको केवल उन फाइलों को शामिल करना होगा जहां आप इस संरचना का उपयोग करना चाहते हैं।

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