2009-03-04 23 views
647

सी ++ में, वहाँ के बीच कोई अंतर नहीं है:सी ++ में 'स्ट्रक्चर' और 'टाइपपीफ स्ट्रक्चर' के बीच अंतर?

struct Foo { ... }; 

और

typedef struct { ... } Foo; 
+0

संबंधित प्रश्न और उत्तर: [सी ++ 11 में उपयोग और टाइपपीफ के बीच अंतर] (http: // stackoverflow।कॉम/प्रश्न/10747810/टाइप-इट-द-फर्क-बीच-टाइप-अप-इन-सी -11) – Joost

+0

यह भी देखें [सी के बारे में संबंधित प्रश्न] (http://stackoverflow.com/questions/252780/why -should-we-typedef-a-struct-so-frequ-in-c) – Raedwald

उत्तर

991

सी ++ में, केवल एक सूक्ष्म अंतर होता है। यह सी से एक होल्डओवर है, जिसमें यह एक फर्क पड़ता है।

सी भाषा मानक (C89 §3.1.2.3, C99 §6.2.3, और C11 §6.2.3) पहचान की विभिन्न श्रेणियों के लिए अलग-अलग नामस्थान, टैग पहचानकर्ता (के लिए struct/union/enum) और साधारण पहचानकर्ता (typedef के लिए और अन्य पहचानकर्ता) सहित जनादेश ।

यदि आप सिर्फ इतना कहा:

struct Foo { ... }; 
Foo x; 

आप एक संकलक त्रुटि मिलती है, क्योंकि Foo केवल टैग नाम स्थान में परिभाषित किया गया है।

आप के रूप में यह घोषणा करने के लिए होगा:

struct Foo x; 

किसी भी समय आप एक Foo का उल्लेख करना चाहते हैं, तो आप हमेशा यह एक struct Foo कॉल करने के लिए होगा। यह कष्टप्रद तेजी से हो जाता है, तो आप एक typedef जोड़ सकते हैं: struct Foo (टैग नाम स्थान में) दोनों अब

struct Foo { ... }; 
typedef struct Foo Foo; 

और सिर्फ सादा Foo (साधारण पहचानकर्ता नाम स्थान में) दोनों एक ही बात का उल्लेख है, और आप स्वतंत्र रूप से कर सकते हैं संरचना कीवर्ड के बिना Foo प्रकार की वस्तुओं की घोषणा करें।


निर्माण:

typedef struct Foo { ... } Foo; 

सिर्फ घोषणा और typedef के लिए एक संक्षिप्त नाम है।


अंत में,

typedef struct { ... } Foo; 

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


सी ++, सभी struct/union/enum/class घोषणाओं में कार्य की तरह वे परोक्ष typedef 'एड कर रहे हैं, जब तक कि नाम ही नाम के साथ एक और घोषणा से छिपा हुआ नहीं है। पूर्ण विवरण के लिए Michael Burr's answer देखें।

+38

जबकि आप जो कहते हैं वह सच है, AFAIK, कथन, 'typedef struct {...} Foo;' एक अज्ञात संरचना के लिए एक उपनाम बनाता है। – dirkgently

+22

अच्छी पकड़, "टाइपपीफ स्ट्रक्चर फू {...} फू;" के बीच एक सूक्ष्म अंतर है और "टाइपपीफ स्ट्रक्चर {...} फू;"। –

+7

सी में, संरचना टैग, यूनियन टैग और गणना टैग ऊपर वर्णित अनुसार दो का उपयोग करके (संरचना और संघ) की बजाय एक नामस्थान साझा करते हैं; टाइपपीफ नामों के लिए संदर्भित नामस्थान वास्तव में अलग है। इसका मतलब है कि आपके पास 'यूनियन एक्स {...}; दोनों नहीं हो सकते हैं; और 'संरचना x {...};' एक ही दायरे में –

-2

वहाँ सी ++ में कोई अंतर नहीं है, लेकिन मैं सी में मानना ​​है कि यह आप के बिना struct फू के उदाहरण की घोषणा करने की अनुमति होगी स्पष्ट रूप से कर रहे हैं:

struct Foo bar; 
+3

@ dirkgently के उत्तर को देखें --- वहां ** ** एक अंतर है, लेकिन यह सूक्ष्म है। –

26

वहां एक अंतर है, लेकिन सूक्ष्म। इसे इस तरह देखो: struct Foo एक नया प्रकार प्रस्तुत करता है। दूसरा नाम एक अज्ञात struct प्रकार के लिए Foo (और एक नया प्रकार नहीं) नामक उपनाम बनाता है।

7.1.3 typedef विनिर्देशक

1 [...]

एक नाम typedef विनिर्देशक साथ घोषित एक typedef-नाम हो जाता है। इसकी घोषणा के दायरे में, टाइपपीफ-नाम एक कीवर्ड के समरूप रूप से समतुल्य है और में पहचानकर्ता के साथ जुड़े प्रकार को नाम 8 में वर्णित तरीके से नामित करता है। टाइपिफ़-नाम इस प्रकार एक अन्य प्रकार का समानार्थी है। एक टाइपिफ़-नाम एक नया प्रकार क्लास घोषणा (9.1) या enum घोषणा के तरीके को पेश नहीं करता है।

8 typedef घोषणा एक अनाम वर्ग (या enum), पहली typedef नाम घोषणा द्वारा घोषित उस वर्ग प्रकार (या enum प्रकार) होने के लिए परिभाषित करता है वर्ग प्रकार निरूपित करने के लिए प्रयोग किया जाता है (या enum प्रकार) लिंक प्रयोजनों के लिए केवल (3.5)। [उदाहरण:

typedef struct { } *ps, S; // S is the class name for linkage purposes 

तो, एक typedef हमेशा एक अन्य प्रकार के लिए एक प्लेसहोल्डर/पर्याय के रूप में प्रयोग किया जाता है।

54

एक और महत्वपूर्ण अंतर: typedef एस को आगे घोषित नहीं किया जा सकता है। तो typedef विकल्प के लिए आपको फ़ाइल typedef वाली फ़ाइल का अर्थ है, जिसका अर्थ है कि #include एस .h में यह भी शामिल है कि फ़ाइल को सीधे इसकी आवश्यकता है या नहीं, और इसी तरह। यह बड़ी परियोजनाओं पर आपके निर्माण के समय को निश्चित रूप से प्रभावित कर सकता है।

typedef के बिना, कुछ मामलों में आप सिर्फ अपने .h फ़ाइल के शीर्ष पर struct Foo; के आगे घोषणा जोड़ सकते हैं, और केवल #include अपने .cpp फ़ाइल में struct परिभाषा।

+0

संरचना की परिभाषा को उजागर करने का निर्माण समय को क्यों प्रभावित करता है? क्या संकलक अतिरिक्त जांच करता है भले ही उसे टाइप करने की आवश्यकता नहीं है (टाइपिफ़ विकल्प दिया गया है, ताकि संकलक परिभाषा को जानता हो) जब यह __Foo * nextFoo; __ जैसा कुछ दिखाई देता है? – Rich

+2

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

+0

कृपया पिछली टिप्पणीकर्ता (पोस्ट के मालिक के अलावा) कृपया। मैं लगभग आपका जवाब याद किया। लेकिन सूचना के लिए धन्यवाद। – Rich

198

this DDJ article में, दान साक्स एक छोटा सा क्षेत्र है जहां कीड़े के माध्यम से रेंगना कर सकते हैं अगर आप अपने structs typedef नहीं है बताते हैं (और वर्गों!):

आप चाहते हैं, तो आप कल्पना कर सकते हैं कि सी ++ एक typedef उत्पन्न करता है हर टैग नाम के लिए, इस तरह के रूप

typedef class string string; 

दुर्भाग्य से, यह नहीं पूरी तरह सटीक है। काश यह आसान था, लेकिन यह नहीं है।सी ++, सी

उदाहरण के लिए साथ असंगतियां शुरू करने के बिना structs, यूनियनों, या enums के लिए इस तरह के typedefs उत्पन्न नहीं कर सकते एक सी कार्यक्रम दोनों एक समारोह और एक struct नामित स्थिति वाणी लगता है:

int status(); struct status; 

फिर से, यह खराब अभ्यास हो सकता है, लेकिन यह सी है। इस कार्यक्रम में, स्थिति ( स्वयं) फ़ंक्शन को संदर्भित करती है; संरचना स्थिति प्रकार को संदर्भित करती है।

तो सी ++ स्वचालित रूप से टैग के लिए typedefs, फिर जब आप इस कार्यक्रम सी ++ के रूप में संकलित, संकलक उत्पन्न होगा उत्पन्न किया:

typedef struct status status; 

दुर्भाग्य से, इस प्रकार का नाम होगा समारोह नाम के साथ संघर्ष, और प्रोग्राम संकलित नहीं होगा। यह क्यों है C++ प्रत्येक टैग के लिए टाइपपीफ उत्पन्न नहीं कर सकता है।

सी ++ में, टैग बस typedef नाम की तरह कार्य, सिवाय इसके कि एक कार्यक्रम एक ही नाम और एक टैग के रूप एक ही दायरे के साथ एक वस्तु, क्रिया, या प्रगणक घोषणा कर सकते हैं। उस स्थिति में, ऑब्जेक्ट, फ़ंक्शन, या एन्युमरेटर नाम टैग नाम छुपाता है। कार्यक्रम टैग नाम के सामने केवल कीवर्ड वर्ग, संरचना, संघ, या enum (उपयुक्त के रूप में) का उपयोग कर टैग नाम का संदर्भ ले सकता है। से युक्त एक प्रकार का नाम टैग के बाद एक विस्तृत प्रकार-विनिर्देशक है। उदाहरण के लिए, संरचना स्थिति और enum महीने विस्तृत-प्रकार-विनिर्देशक हैं।

इस प्रकार, एक सी कार्यक्रम दोनों शामिल है कि:

int status(); struct status; 

ही व्यवहार करने के तरीके सी ++ के रूप में संकलित। अकेले नाम की स्थिति फ़ंक्शन को संदर्भित करती है। कार्यक्रम प्रकार को केवल विस्तृत-प्रकार-विनिर्देशक संरचना स्थिति का उपयोग कर टाइप कर सकता है।

तो यह प्रोग्रामों में बग को कैसे रेंगने की अनुमति देता है? Listing 1 में प्रोग्राम पर विचार करें। यह प्रोग्राम क्लास फू को डिफ़ॉल्ट कन्स्ट्रक्टर, और एक रूपांतरण ऑपरेटर के साथ परिभाषित करता है जो एक foo ऑब्जेक्ट को char const * में परिवर्तित करता है। अभिव्यक्ति

p = foo(); 

मुख्य में एक foo वस्तु का निर्माण और रूपांतरण ऑपरेटर लागू करना चाहिए। बाद उत्पादन बयान

cout << p << '\n'; 

वर्ग foo प्रदर्शित करना चाहिए, लेकिन यह नहीं करता है। यह फ़ंक्शन foo प्रदर्शित करता है।

यह आश्चर्यजनक परिणाम होता है क्योंकि प्रोग्राम में हेडर lib.h Listing 2 में दिखाया गया है। यह हेडर फ़ू नामक फ़ंक्शन को परिभाषित करता है। फ़ंक्शन नाम foo वर्ग नाम foo को छुपाता है, इसलिए मुख्य में foo का संदर्भ फ़ंक्शन को संदर्भित करता है, न कि वर्ग। मुख्य वर्ग के लिए केवल द्वारा एक सविस्तार-प्रकार-विनिर्देशक का उपयोग कर के रूप में

p = class foo(); 

में जिस तरह से इस तरह के भ्रम की स्थिति से बचने के लिए उल्लेख कर सकते हैं, के दौरान कार्यक्रम वर्ग के नाम के लिए निम्नलिखित typedef जोड़ने के लिए है foo:

typedef class foo foo; 
तुरंत पहले या वर्ग परिभाषा के बाद

। यह typedef प्रकार का नाम foo और समारोह नाम foo ( पुस्तकालय से) है कि एक संकलन समय त्रुटि ट्रिगर करेंगे जो संघर्ष का कारण बनता है।

मैं कोई भी, जो वास्तव में पाठ्यक्रम के एक मामले के रूप में इन typedefs लिखते हैं के बारे में पता। इसके लिए बहुत सारे अनुशासन की आवश्यकता है। चूंकि जैसे Listing 1 में त्रुटियों की घटनाएं शायद छोटी हैं, तो आप कभी भी इस समस्या को से पहले कभी नहीं चलाते हैं। लेकिन अगर आपके सॉफ्टवेयर में किसी त्रुटि शारीरिक चोट के कारण हो सकता, तो आप typedefs कोई चाहे कितना संभावना नहीं त्रुटि लिखना चाहिए।

मैं कल्पना नहीं कर सकते क्यों क्या कभी किसी ने एक समारोह के साथ एक वर्ग के नाम छुपाने या वर्ग के रूप में एक ही दायरे में नाम आपत्ति चाहते हैं। सी में छुपा नियम एक गलती थी, और उन्हें C++ में कक्षाओं तक विस्तारित नहीं किया जाना चाहिए था। दरअसल, आप गलती को सही कर सकते हैं, लेकिन इसके लिए अतिरिक्त प्रोग्रामिंग अनुशासन और प्रयास की आवश्यकता है जो आवश्यक नहीं होना चाहिए।

+6

यदि आप "कक्षा foo()" को आज़माते हैं और यह विफल रहता है: आईएसओ सी ++ में, "कक्षा foo()" एक अवैध निर्माण है (आलेख को '97 लिखा गया था, मानकीकरण से पहले, ऐसा लगता है)। आप "typedef class foo foo" डाल सकते हैं मुख्य में, तो आप कह सकते हैं "foo();" (क्योंकि तब, टाइपपीफ-नाम फ़ंक्शन के नाम से काफी करीब है)। Syntactically, टी() में, टी एक साधारण प्रकार के विनिर्देशक होना चाहिए। विस्तारित प्रकार विनिर्देशों की अनुमति नहीं है। फिर भी, यह एक अच्छा जवाब है, ज़ाहिर है। –

+0

'लिस्टिंग 1' और' लिस्टिंग 2' लिंक टूटा हुआ है। एक नज़र देख लो। –

+0

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

10

आप टाइपपीफ संरचना के साथ आगे की घोषणा का उपयोग नहीं कर सकते हैं। तो आप यह घोषणा करते अग्रेषित करने के लिए एक वास्तविक नाम नहीं है

struct ही है, एक गुमनाम प्रकार है।

typedef struct{ 
    int one; 
    int two; 
}myStruct; 

इस अभ्यस्त काम की तरह एक आगे घोषणा:

struct myStruct; //forward declaration fails 

void blah(myStruct* pStruct); 

//error C2371: 'myStruct' : redefinition; different basic types 
+0

मुझे फ़ंक्शन प्रोटोटाइप के लिए दूसरी त्रुटि नहीं मिलती है। यह क्यों कहते हैं "पुनर्वितरण; विभिन्न बुनियादी प्रकार"? कंपाइलर को यह जानने की आवश्यकता नहीं है कि MyStruct की परिभाषा कैसा दिखती है, है ना? कोड के टुकड़े से कोई फर्क नहीं पड़ता (टाइपिफ एक, या आगे की घोषणा एक), MyStruct एक संरचना प्रकार इंगित करता है, है ना? – Rich

+0

@Rich यह शिकायत कर रहा है कि नामों का एक संघर्ष है। "MyStruct नामक एक स्ट्रक्चर की तलाश करें" कहने के लिए एक आगे की घोषणा है और फिर टाइपिफ़ है जो नामहीन संरचना को "myStruct" के रूप में नामित कर रहा है। –

+0

आपका मतलब है कि एक ही फाइल में टाइपिफ़ और दोनों घोषणाओं को आगे रखें? मैंने किया, और जीसीसी ने इसे ठीक संकलित किया। myStruct को नामहीन संरचना के रूप में सही ढंग से व्याख्या किया गया है। टैग 'myStruct' टैग नेमस्पेस में रहता है और टाइपेडफ_ड' मायस्ट्रक्चर 'सामान्य नामस्थान में रहता है जहां अन्य पहचानकर्ता फ़ंक्शन नाम, स्थानीय चर नामों में रहते हैं। इसलिए कोई संघर्ष नहीं होना चाहिए..मैं आपको संदेह करता हूं तो मैं आपको अपना कोड दिखा सकता हूं इसमें कोई त्रुटि है। – Rich

0

एक 'typedef struct' और C++ एक 'struct' के बीच एक महत्वपूर्ण अंतर 'typedef structs' में है कि इनलाइन सदस्य initialisation है नहीं होगा काम।

// the 'x' in this struct will NOT be initialised to zero 
typedef struct { int x = 0; } Foo; 

// the 'x' in this struct WILL be initialised to zero 
struct Foo { int x = 0; }; 
+2

** सच नहीं है। दोनों मामलों में 'x' प्रारंभ किया गया है। ** देखें [कोलिरु ऑनलाइन आईडीई में परीक्षण] (http://coliru.stacked-crooked.com/a/46c819ed3fbcf6d8) (मैंने इसे 42 तक शुरू किया ताकि यह शून्य से अधिक स्पष्ट हो कि असाइनमेंट वास्तव में हुआ है)। –

+0

असल में, मैंने इसे विजुअल स्टूडियो 2013 में परीक्षण किया और इसे प्रारंभ नहीं किया गया था। यह एक समस्या थी जिसे हम उत्पादन कोड में पार करते थे। सभी कंपाइलर्स अलग हैं और केवल कुछ मानदंडों को पूरा करना है। – user2796283

0

संरचना डेटा प्रकार बनाना है। टाइपपीफ डेटा प्रकार के लिए उपनाम सेट करना है।

+3

आपको प्रश्न समझ में नहीं आया। – Winter

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