2011-01-15 13 views
28

मैंने देखा है कि सी structs ने पहले कई अलग-अलग तरीकों की घोषणा की है। वह और क्यों, यदि कुछ भी है, तो क्या प्रत्येक अलग होता है?सी संरचना घोषित करने के लिए वाक्य रचनात्मक रूप से उचित तरीका क्या है?

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

struct foo { 
    short a; 
    int b; 
    float c; 
}; 

typedef struct { 
    short d; 
    int e; 
    float f; 
} bar; 

typedef struct _baz { 
    short a; 
    int b; 
    float c; 
} baz; 

int main (int argc, char const *argv[]) 
{ 
    struct foo a; 
    bar b; 
    baz c; 

    return 0; 
} 
+0

यह सी के लिए आपके प्रश्न का उत्तर नहीं देता है, लेकिन मेरा मानना ​​है कि वे सी ++ के लिए सभी सही हैं, हालांकि पहले व्यक्ति को प्राथमिकता दी जाती है। यह सी के विभिन्न संस्करणों के बीच भी बदल सकता है, लेकिन मैं किसी और से बात करने दूँगा, क्योंकि मैं सी/सी ++ के इतिहास पर कोई विशेषज्ञ नहीं हूं। –

+2

सी ++ अलग है: जब आप 'स्ट्रक्चर फू {};' या 'क्लास फू {} लिखते हैं;' वहां, आपको 'typedef' के बिना मुफ्त में 'Foo' मिलता है। –

+0

वे सभी अभी भी काम करेंगे, भले ही वे थोड़ा अलग चीजें कर सकें (जैसे कि आपके नेमस्पेस डब्ल्यू/अतिरिक्त टैग को प्रदूषित करें)। –

उत्तर

31

ठीक है, स्पष्ट अंतर अपने main में दर्शाया गया है:

struct foo a; 
bar b; 
baz c; 

पहले घोषणा एक संयुक्त राष्ट्र typedef एड struct की है और struct कीवर्ड का उपयोग करने की जरूरत है। दूसरा typedef ed अज्ञात struct है, और इसलिए हम typedef नाम का उपयोग करते हैं। तीसरा पहला और दूसरा दोनों जोड़ता है: आपका उदाहरण baz (जो आसानी से छोटा है) का उपयोग करता है लेकिन उसी प्रभाव के लिए आसानी से struct _baz का उपयोग कर सकता है।

अद्यतन: larsmans' answer एक और आम मामला बताता है जहां आपको कम से कम struct x { } का उपयोग एक लिंक सूची बनाने के लिए करना है। दूसरा मामला यहां संभव नहीं होगा (जब तक आप सैनिटी को त्यागें और void * का उपयोग करें) क्योंकि struct अज्ञात है, और typedef तब तक नहीं होता है जब तक struct परिभाषित नहीं किया जाता है, आपको कोई प्रकार (सुरक्षित-सुरक्षित)) struct के लिए सूचक स्वयं टाइप करें। पहला संस्करण इस उपयोग के लिए ठीक काम करता है, लेकिन तीसरा आम तौर पर मेरे अनुभव में पसंद किया जाता है। उसके लिए उसे कुछ प्रतिनिधि दें।

नामस्थान प्लेसमेंट में एक और सूक्ष्म अंतर है। सी में, struct टैग अन्य नामों से अलग नामस्थान में रखा गया है, लेकिन typedef नाम नहीं हैं। तो निम्नलिखित कानूनी है:

struct test { 
    // contents 
}; 

struct test *test() { 
    // contents 
} 

लेकिन क्योंकि यह अस्पष्ट होगा क्या नाम test है निम्नलिखित, नहीं है:

typedef struct { 
    // contents 
} test; 

test *test() { 
    // contents 
} 

typedef नाम छोटा (हमेशा एक प्लस) बनाता है, लेकिन यह इसे अपने चर और कार्यों के समान नामस्थान में रखता है। आम तौर पर यह कोई मुद्दा नहीं है, लेकिन यह सरल शॉर्टिंग से परे एक सूक्ष्म अंतर है।

+0

महान उत्तर, धन्यवाद! नामस्थान मुद्दे के लिए –

+0

+1। –

+0

टैग और टाइपपीफ दोनों के लिए समान नाम का उपयोग करना अवैध होगा? या एक अच्छा विचार नहीं है? या यह बिल्कुल ठीक है? उदाहरण के लिए: typedef struct mystruct {} mystruct; – SeanRamey

27

यह काफी हद तक व्यक्तिगत पसंद की बात है। मैं नए प्रकार को पूंजी पत्र से शुरू करने वाला नाम देना चाहता हूं और struct को छोड़ना चाहता हूं, इसलिए मैं आमतौर पर typedef struct { ... } Foo लिखता हूं। इसका मतलब है कि मैं struct Foo लिख नहीं सकता।

अपवाद तब होता है जब struct में अपने स्वयं के प्रकार के लिए एक सूचक होता है, उदा।

typedef struct Node { 
    // ... 
    struct Node *next; 
} Node; 

इस मामले में आप भी struct Node प्रकार की घोषणा करने की जरूरत है के बाद से typedefstruct परिभाषा के दायरे में दायरे में नहीं है। ध्यान दें कि दोनों नाम समान हो सकते हैं (मुझे यकीन नहीं है कि अंडरस्कोर सम्मेलन का जन्म कहाँ हुआ, लेकिन मुझे लगता है कि पुराने सी कंपाइलर typedef struct X X; को संभाल नहीं सकते थे)।

+0

दोह! मैं स्पष्ट "लिंक्ड सूची" उपयोग केस भूल गया। +1 –

6

आपके सभी उपयोग वाक्य रचनात्मक रूप से सही हैं।मैं निम्नलिखित उपयोग पसंद करते हैं

/* forward declare all structs and typedefs */ 
typedef struct foo foo; 
. 
. 
/* declare the struct itself */ 
struct foo { 
    short a; 
    int b; 
    foo* next; 
}; 

गौर करें कि यह आसानी से struct खुद की घोषणा के अंदर पहले से ही typedef उपयोग करने के लिए अनुमति देता है, और कहा कि यहां तक ​​कि के लिए struct कि एक दूसरे को परस्पर संदर्भ।

+3

+1 उस क्षेत्र के लिए +1 जो मैंने याद किया था, और यदि आप अपने हेडर में 'टाइपपीफ स्ट्रक्चर फू फू' का उपयोग करते हैं और 'स्ट्रक्चर फू' की परिभाषा प्रदान नहीं करते हैं, तो उपयोगकर्ता कोड में एक अपारदर्शी पॉइंटर होगा (यानी वे पास कर सकते हैं 'foo *' पॉइंटर्स उन्हें लाइब्रेरी फ़ंक्शंस से प्राप्त करते हैं और उन्हें प्राप्त करते हैं लेकिन आंतरिक सदस्यों तक नहीं पहुंच सकते हैं।) यह डेटा encapsulation के लिए अच्छा है, और एक सामान्य मुहावरे: मानक 'फ़ाइल *' प्रकार इस तरह का एक उदाहरण है। –

4

भ्रम इस बारे में आता है क्योंकि कुछ घोषणाएं वास्तव में तीन सी संरचनाओं की घोषणा कर रही हैं। आपको के बीच अंतर को ध्यान में रखना होगा 1. एक टाइपिफ़ घोषणा, 2. एक संरचना परिभाषा, और 3. एक संरचना घोषणा।

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

चलो प्रत्येक घोषणा को बदले में देखें।

//================================================ 
struct foo { 
    short a; 
    int b; 
    float c; 
}; 

यहां हम सबसे बुनियादी संरचना परिभाषा वाक्यविन्यास का उपयोग कर रहे हैं। हम एक सी प्रकार कि बाद में निम्न सिंटैक्स का उपयोग कर उस प्रकार के चर घोषित करने के लिए इस्तेमाल किया जा सकता के रूप में परिभाषित कर रहे हैं foo:

foo myFoo; // Declare a struct variable of type foo. 

// =============== ======================================यह अगली घोषणा उसमें पिछले वाक्यविन्यास की तरह है यह एक सी प्रकार की घोषणा करता है, लेकिन यह टाइपपीफ वाक्यविन्यास का उपयोग करता है। चलो पिछले मूल घोषणा का उपयोग करके इसे अपने घटकों में तोड़ दें।

typedef foo bar; // Declare bar as a variable type, the alias of foo. 

bar myBar;  // This is ssemantically the same as: foo myBar; 

अब पिछले वाक्यविन्यास और वॉयला के साथ "foo" को प्रतिस्थापित करें!

typedef struct { 
    short d;  
    int e; 
    float f; 
} bar; 

//================================================================== 
typedef struct _baz { 
    short a; 
    int b; 
    float c; 
} baz; 

उपर्युक्त वाक्यविन्यास घोषणाओं के निम्नलिखित अनुक्रम के बराबर है।

struct _baz { 
    short a; 
    int b; 
    float c; 
} 

typedef _baz baz; // Declare baz as an alias for _baz. 

baz myBaz;  // Is the same as: _baz myBaz; 

//======================================================== 
संबंधित मुद्दे