दिलचस्प पोस्ट
बैश स्क्रिप्ट से ओएस खोजें संदर्भ प्रकार अभी भी रेफरी से पास की जरूरत है? jquery $ .ajax से कोण $ http क्या कोई व्यावहारिक HTTP हैडर लंबाई सीमा है? सीखना WebGL और three.js स्ट्रिंग को bool के साथ int को परिवर्तित करें / C ++ में विफल मेरे एप बंडल में प्लान करने के लिए एनएसडस्ट्री लिखना क्या एक jquery घटना है कि आग जब एक नया नोड dom में डाला जाता है? स्विफ्ट 3 ग़लत स्ट्रिंग इंटरप्रोलेशन जिसमें अन्तर्निहित अवांछित विकल्प हैं प्रगति के लिए कस्टम Drawable बर / प्रगति Dialog प्रवेश में एक तरह की क्वेरी क्यों किसी भी रिकॉर्ड वापस नहीं करता है? UITableView पर बटन को कैसे रखा जाए जो IOS में तालिका के साथ स्क्रॉल नहीं करेगा मोंगोज़ के माध्यम से मोंगो सरणी में वस्तुओं को पुश करें मेरे कंसोल में सभी कंसोल.लॉग स्टेटमेंट को जल्दी और आसानी से कैसे अक्षम करें? Django में – मॉडल विरासत – क्या यह आपको एक मूल मॉडल के गुण को ओवरराइड करने की अनुमति देता है?

हमें सी यूनियनों की आवश्यकता क्यों है?

यूनियनों को कब उपयोग किया जाना चाहिए? हमें आपकी प्रतिक्रिया का बेसब्री से इंतेज़ार हैं।

वेब के समाधान से एकत्रित समाधान "हमें सी यूनियनों की आवश्यकता क्यों है?"

यूनियनों को अक्सर पूर्णांक और फ़्लोट्स के द्विआधारी प्रतिनिधित्व के बीच परिवर्तित करने के लिए उपयोग किया जाता है:

union { int i; float f; } u; // Convert floating-point bits to integer: uf = 3.14159f; printf("As integer: %08x\n", ui); 

हालांकि यह सी मानक के अनुसार तकनीकी रूप से अपरिभाषित व्यवहार है (आप केवल उस क्षेत्र को पढ़ना चाह रहे हैं जो हाल ही में लिखे गए थे), यह लगभग किसी भी संकलक में अच्छी तरह से परिभाषित तरीके से कार्य करेगा।

यूनियनों को कभी-कभी सी में छद्म-बहुरूपता को लागू करने के लिए उपयोग किया जाता है, कुछ संरचना को यह दर्शाता है कि यह किस प्रकार का ऑब्जेक्ट है, और फिर संभव प्रकार के संयोजनों को एक साथ जोड़कर कुछ टैग देता है:

 enum Type { INTS, FLOATS, DOUBLE }; struct S { Type s_type; union { int s_ints[2]; float s_floats[2]; double s_double; }; }; void do_something(struct S *s) { switch(s->s_type) { case INTS: // do something with s->s_ints break; case FLOATS: // do something with s->s_floats break; case DOUBLE: // do something with s->s_double break; } } 

इससे struct S का आकार 28 की बजाय केवल 12 बाइट्स हो सकता है।

यूनियनों एंबेडेड प्रोग्रामिंग या ऐसी परिस्थितियों में विशेष रूप से उपयोगी होती हैं जहां हार्डवेयर / मेमरी की सीधी पहुंच की आवश्यकता होती है। यहां एक तुच्छ उदाहरण है:

 typedef union { struct { unsigned char byte1; unsigned char byte2; unsigned char byte3; unsigned char byte4; } bytes; unsigned int dword; } HW_Register; HW_Register reg; 

तो आप निम्नानुसार reg का उपयोग कर सकते हैं:

 reg.dword = 0x12345678; reg.bytes.byte3 = 4; 

एंडियनेंस (बाइट ऑर्डर) और प्रोसेसर आर्किटेक्चर कोर्स की महत्वपूर्ण हैं।

एक अन्य उपयोगी सुविधा बिट संशोधक है:

 typedef union { struct { unsigned char b1:1; unsigned char b2:1; unsigned char b3:1; unsigned char b4:1; unsigned char reserved:4; } bits; unsigned char byte; } HW_RegisterB; HW_RegisterB reg; 

इस कोड के साथ आप रजिस्टर / मेमोरी पते में सीधे एक बिट का उपयोग कर सकते हैं:

 x = reg.bits.b2; 

निम्न स्तर प्रणाली प्रोग्रामिंग एक उचित उदाहरण है।

आईआईआरसी, मैंने यूनियनों को घटक बिट्स में हार्डवेयर रजिस्टरों को तोड़ने के लिए उपयोग किया है I इसलिए, आप एक 8-बिट रजिस्टर (जैसा कि मैंने उस दिन किया था 😉 में, घटक बिट्स में प्रवेश कर सकते हैं।

(मैं सटीक सिंटैक्स भूल गया हूं, लेकिन …) यह संरचना एक नियंत्रण रजिस्टर को एक नियंत्रण_बाइट या व्यक्तिगत बिट्स के माध्यम से एक्सेस करने की अनुमति देगा। किसी निश्चित एंडियननेस के लिए सही रजिस्टर बिट्स पर बिट्स का मानचित्र सुनिश्चित करने के लिए यह महत्वपूर्ण होगा।

 typedef union { unsigned char control_byte; struct { unsigned int nibble : 4; unsigned int nmi : 1; unsigned int enabled : 1; unsigned int fired : 1; unsigned int control : 1; }; } ControlRegister; 

मैंने इसे दोहरी पुस्तकालयों में वस्तु उन्मुख विरासत के लिए प्रतिस्थापन के रूप में देखा है।

उदाहरण के लिए

  Connection / | \ Network USB VirtualConnection 

यदि आप उपरोक्त में से कोई एक "कनेक्शन" कनेक्शन चाहते हैं, तो आप ऐसा कुछ लिख सकते हैं:

 struct Connection { int type; union { struct Network network; struct USB usb; struct Virtual virtual; } }; 

उदाहरण का उपयोग लिबिनेटिटी में: http://git.0x539.de/?p=infinote.git;a=blob;f=libinfinity/common/inf-session.c;h=3e887f0d63bd754c6b5ec232948027cbbf4d61fc;hb=HEAD#l74

यूनियन डेटा सदस्यों को अनुमति देते हैं जो समान मेमोरी साझा करने के लिए परस्पर अनन्य हैं। यह बहुत महत्वपूर्ण है जब स्मृति अधिक दुर्लभ है, जैसे एम्बेडेड सिस्टम में।

निम्नलिखित उदाहरण में:

 union { int a; int b; int c; } myUnion; 

यह संघ 3 अलग-अलग मूल्यों के बजाय एक एकल int की जगह लेगा। यदि उपयोगकर्ता ने के मान सेट किया है , और फिर बी के मान को सेट किया है, तो वह किसी के मान को ओवरराइट करेगा क्योंकि वे दोनों एक ही मेमोरी स्थान साझा कर रहे हैं।

उपयोग के बहुत सारे बस grep union /usr/include/* या समान निर्देशिकाओं में अधिकांश मामलों में union struct में लपेटता है और struct एक सदस्य ने यूनियन में कौन सी तत्व का उपयोग किया है। उदाहरण के लिए वास्तविक जीवन कार्यान्वयन के लिए चेकआउट man elf

यह बुनियादी सिद्धांत है:

 struct _mydata { int which_one; union _data { int a; float b; char c; } foo; } bar; switch (bar.which_one) { case INTEGER : /* access bar.foo.a;*/ break; case FLOATING : /* access bar.foo.b;*/ break; case CHARACTER: /* access bar.foo.c;*/ break; } 

यहां मेरे स्वयं के कोडबेस से एक यूनियन का एक उदाहरण है (स्मृति से और paraphrased इसलिए यह सटीक नहीं हो सकता है)। इसका उपयोग मैं अनुवादित एक अनुवादक में भाषा तत्वों को संग्रहीत करने के लिए किया गया था। उदाहरण के लिए, निम्न कोड:

 set a to b times 7. 

निम्नलिखित भाषा तत्व शामिल हैं:

  • प्रतीक [सेट]
  • चर [एक]
  • प्रतीक [करने के लिए]
  • चर [ख]
  • प्रतीक [बार]
  • निरंतर [7]
  • प्रतीक[।]

भाषा तत्वों को ' #define ' मानों के रूप में परिभाषित किया गया था:

 #define ELEM_SYM_SET 0 #define ELEM_SYM_TO 1 #define ELEM_SYM_TIMES 2 #define ELEM_SYM_FULLSTOP 3 #define ELEM_VARIABLE 100 #define ELEM_CONSTANT 101 

और प्रत्येक तत्व को स्टोर करने के लिए निम्नलिखित संरचना का उपयोग किया गया था:

 typedef struct { int typ; union { char *str; int val; } } tElem; 

तो प्रत्येक तत्व का आकार अधिकतम संघ का आकार था (संघ के लिए प्रकार और 4 बाइट्स के लिए 4 बाइट्स, यद्यपि ये सामान्य मान हैं, कार्यान्वयन पर वास्तविक आकार)।

एक "सेट" तत्व बनाने के लिए, आप इसका प्रयोग करेंगे:

 tElem e; e.typ = ELEM_SYM_SET; 

एक "चर [बी]" तत्व बनाने के लिए, आप इसका प्रयोग करेंगे:

 tElem e; e.typ = ELEM_VARIABLE; e.str = strdup ("b"); // make sure you free this later 

"स्थिर [7]" तत्व बनाने के लिए, आप इसका प्रयोग करेंगे:

 tElem e; e.typ = ELEM_CONSTANT; e.val = 7; 

और आप इसे आसानी से फ़्लोट्स ( float flt struct ratnl {int num; int denom;} ) या struct ratnl {int num; int denom;} ( struct ratnl {int num; int denom;} ) और अन्य प्रकारों को शामिल करने के लिए विस्तारित कर सकते हैं।

मूल आधार यह है कि str और val स्मृति में संगत नहीं हैं, वे वास्तव में ओवरलैप करते हैं, इसलिए यह स्मृति के एक ही ब्लॉक पर अलग-अलग दृश्य प्राप्त करने का एक तरीका है, यहां इलस्ट्रेट किया गया है, जहां संरचना मेमोरी स्थान 0x1010 और पूर्णांक पर आधारित है और संकेतक दोनों 4 बाइट हैं:

  +-----------+ 0x1010 | | 0x1011 | typ | 0x1012 | | 0x1013 | | +-----+-----+ 0x1014 | | | 0x1015 | str | val | 0x1016 | | | 0x1017 | | | +-----+-----+ 

यदि यह एक संरचना में ही था, तो यह ऐसा दिखेगा:

  +-------+ 0x1010 | | 0x1011 | typ | 0x1012 | | 0x1013 | | +-------+ 0x1014 | | 0x1015 | str | 0x1016 | | 0x1017 | | +-------+ 0x1018 | | 0x1019 | val | 0x101A | | 0x101B | | +-------+ 

मैं कहूंगा कि यह स्मृति को फिर से उपयोग करना आसान बनाता है जिसका उपयोग अलग-अलग तरीकों से किया जा सकता है, यानी मेमोरी बचत। उदाहरण के लिए, आप कुछ "वेरिएंट" स्ट्रेट करना चाहते हैं जो एक छोटी स्ट्रिंग के साथ-साथ संख्या को सहेज सकते हैं:

 struct variant { int type; double number; char *string; }; 

एक 32 बिट सिस्टम में इस प्रकार कम से कम 96 बिट या 12 बाइट का उपयोग प्रत्येक variant के variant

एक संघ का उपयोग करके आप आकार को 64 बिट या 8 बाइट्स तक कम कर सकते हैं:

 struct variant { int type; union { double number; char *string; } value; }; 

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

किसी विशिष्ट अवसर के बारे में सोचना मुश्किल है, जब आपको इस प्रकार की लचीली संरचना की आवश्यकता होती है, संभवतः एक संदेश प्रोटोकॉल में जहां आप विभिन्न आकार के संदेश भेजना चाहते हैं, लेकिन फिर भी शायद बेहतर और अधिक प्रोग्रामर अनुकूल विकल्प हैं

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

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

 typedef union MyUnion MYUNION; union MyUnion { int MyInt; float MyFloat; }; 

MyUnion में केवल एक इंट या एक फ्लोट शामिल होगा, जिस पर आप सबसे हाल ही में सेट करेंगे । ऐसा करने से:

 MYUNION u; u.MyInt = 10; 

यू अब 10 के बराबर एक इंट है;

 u.MyFloat = 1.0; 

यू अब 1.0 के बराबर फ्लोट रखता है। यह अब एक int नहीं रखता है जाहिर है अब अगर आप कोशिश करते हैं और printf करते हैं ("MyInt =% d", u.MyInt); तो आप शायद एक त्रुटि प्राप्त करने जा रहे हैं, हालांकि मुझे विशिष्ट व्यवहार के बारे में अनिश्चित है

संघ का आकार अपने सबसे बड़े क्षेत्र के आकार से तय होता है, इस मामले में फ्लोट

यूनियनों का उपयोग तब किया जाता है जब आप हार्डवेअर, डिवाइस या नेटवर्क प्रोटोकॉल द्वारा परिभाषित मॉडल स्ट्रेंक्ट्स करना चाहते हैं, या जब आप बड़ी संख्या में ऑब्जेक्ट बना रहे हैं और स्थान को सहेजना चाहते हैं आपको वास्तव में उनके 95% समय की आवश्यकता नहीं है, हालांकि आसान-डी-डिबग कोड के साथ रहें

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

 typedef union { UINT8 buffer[PACKET_SIZE]; // Where the packet size is large enough for // the entire set of fields (including the payload) struct { UINT8 size; UINT8 cmd; UINT8 payload[PAYLOAD_SIZE]; UINT8 crc; } fields; }PACKET_T; // This should be called every time a new byte of data is ready // and point to the packet's buffer: // packet_builder(packet.buffer, new_data); void packet_builder(UINT8* buffer, UINT8 data) { static UINT8 received_bytes = 0; // All range checking etc removed for brevity buffer[received_bytes] = data; received_bytes++; // Using the struc only way adds lots of logic that relates "byte 0" to size // "byte 1" to cmd, etc... } void packet_handler(PACKET_T* packet) { // Process the fields in a readable manner if(packet->fields.size > TOO_BIG) { // handle error... } if(packet->fields.cmd == CMD_X) { // do stuff.. } } 

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

क्या COM अंतरफलक में उपयोग किया जाता है कि VARIANT बारे में? इसमें दो फ़ील्ड हैं – "टाइप" और एक यूनियन जो "टाइप" फ़ील्ड के आधार पर वास्तविक मान रखता है।

स्कूल में, मैंने इस तरह यूनियनों का इस्तेमाल किया:

 typedef union { unsigned char color[4]; int new_color; } u_color; 

मैंने इसे इस्तेमाल करने के बजाय रंग और अधिक आसानी से रंगों को संभालने के लिए इस्तेमाल किया << ऑपरेटर, मुझे अपने चार सरणी के विभिन्न सूचकांक के माध्यम से जाना था।

जब मैं एम्बेडेड डिवाइसों के लिए कोडिंग था तब मैं संघ का उपयोग करता था मेरे पास C int है जो 16 बिट लंबा है और जब मुझे / स्टोर से EEPROM को पढ़ने की आवश्यकता होती है तो मुझे उच्च 8 बिट और निम्न 8 बिट प्राप्त करना होगा तो मैं इस तरह से इस्तेमाल किया:

 union data { int data; struct { unsigned char higher; unsigned char lower; } parts; }; 

इसे बदलने की आवश्यकता नहीं होती है ताकि कोड पढ़ने में आसान हो।

दूसरी तरफ, मैंने कुछ पुराने सी + + एसटीएल कोड देखा जो स्टॉल आबंटक के लिए यूनियन का इस्तेमाल करता था। यदि आप रुचि रखते हैं, तो आप एसजीआई स्टैट स्रोत कोड पढ़ सकते हैं। यहां इसका एक टुकड़ा है:

 union _Obj { union _Obj* _M_free_list_link; char _M_client_data[1]; /* The client sees this. */ }; 
  • एक फ़ाइल जिसमें विभिन्न रिकॉर्ड प्रकार हैं
  • एक नेटवर्क इंटरफेस जिसमें विभिन्न अनुरोध प्रकार शामिल हैं।

इस पर एक नज़र डालें: X.25 बफर कमांड हैंडलिंग

कई संभव X.25 आदेशों में से एक को बफर में प्राप्त किया जाता है और सभी संभव संरचनाओं के एक यूनियन का उपयोग करके उसे संभाला जाता है।

सी के प्रारंभिक संस्करणों में, सभी संरचना घोषणाएं क्षेत्र का एक सामान्य समूह साझा करती हैं। दिया हुआ:

 struct x {int x_mode; int q; float x_f}; struct y {int y_mode; int q; int y_l}; struct z {int z_mode; char name[20];}; 

एक कंपाइलर अनिवार्य रूप से संरचनाओं के आकार (और संभावित रूप से संरेखण) की एक तालिका का निर्माण करेगा, और संरचनाओं के सदस्यों के नाम, प्रकार और ऑफ़सेट की एक अलग तालिका। संकलक उस ट्रैक का नज़र नहीं रखता जिसके सदस्यों में कौन से संरचनाएं थीं, और दो संरचनाओं को एक ही नाम के साथ एक सदस्य होने की अनुमति दें, यदि प्रकार और ऑफ़सेट मिलान (जैसा कि struct x और struct y का सदस्य q ) के साथ होता है। यदि पी किसी भी प्रकार की संरचना के लिए एक सूचक था, तो p-> q "ऑफसेट ऑफ पॉइंट" पी जोड़ता है और परिणामी पते से "इंट" प्राप्त करता है।

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

उस अंतराल को भरने के लिए यूनियनों की क्षमता का एक अनिवार्य हिस्सा यह था कि एक सदस्य के सदस्य के लिए एक सूचक एक सूचक में किसी भी संघ में परिवर्तित किया जा सकता है, और किसी भी यूनियन को एक संकेतक किसी भी सदस्य को सूचक में परिवर्तित किया जा सकता है। जबकि सी 8 9 मानक ने स्पष्ट रूप से यह नहीं कहा कि सीधे U* लिए T* कास्टिंग करना किसी सूचक प्रकार को किसी भी संघ के प्रकार को T और U युक्त करता है, और फिर U* लिए कास्ट करने के बराबर था, इसका कोई परिभाषित व्यवहार नहीं था उत्तरार्द्ध डाली अनुक्रम उपयोग किया जाने वाला यूनियन प्रकार से प्रभावित होगा, और स्टैंडर्ड ने T से U लिए सीधे कलाकारों के लिए किसी भी विपरीत शब्दों को निर्दिष्ट नहीं किया। इसके अलावा, ऐसे मामलों में जहां किसी समारोह को अज्ञात मूल का सूचक मिला, T* माध्यम से एक वस्तु लिखने का व्यवहार, T* को U* परिवर्तित कर, और फिर U* माध्यम से ऑब्जेक्ट को पढ़ने से सदस्य के माध्यम से यूनियन लिखने के बराबर होगा प्रकार T के प्रकार और U प्रकार के रूप में पढ़ना, जो कुछ मामलों में मानक-परिभाषित होगा (जैसे, सामान्य प्रारंभिक अनुक्रम सदस्यों तक पहुंचने पर) और बाकी के लिए कार्यान्वयन-परिभाषित (अपरिभाषित होने के बजाय) हालांकि, यूनियन प्रकार की वास्तविक वस्तुओं के साथ सीआईएस की गारंटी देने के कार्यक्रमों के लिए यह दुर्लभ था, लेकिन इस तथ्य का फायदा उठाने के लिए यह अधिक सामान्य था कि अज्ञात मूल के ऑब्जेक्ट को पॉइंटर्स जैसे यूनियन सदस्यों के साथ व्यवहार करना था और इसके साथ जुड़े व्यवहार की गारंटी भी थी।

यूनियन महान हैं मैंने देखा है कि यूनियनों का एक चतुर उपयोग एक घटना को परिभाषित करते समय किया जाता है। उदाहरण के लिए, आप तय कर सकते हैं कि एक घटना 32 बिट है

अब, उस 32 बिट्स के भीतर, आप ईवेंट के प्रेषक के पहचानकर्ता के लिए पहले 8 बिट्स को निर्दिष्ट करना चाहते हैं … कभी-कभी आप पूरी तरह से इस घटना के साथ काम करते हैं, कभी-कभी आप इसे काटना और इसके घटकों की तुलना करते हैं यूनियन आपको दोनों को करने की लचीलापन देते हैं।

 संघ कार्यक्रम
 {
   अहस्ताक्षरित लंबे घटनाकोड;
   अहस्ताक्षरित चार घटनाएं [4];
 };

एक सरल और बहुत ही उपयोगी उदाहरण है ….

कल्पना कीजिए:

आपके पास एक uint32_t array[2] और बाइट श्रृंखला के तीसरे और चौथे बाइट तक पहुंचना चाहते हैं। आप *((uint16_t*) &array[1]) लेकिन यह दुख की बात है कि सख्त अलियासिंग नियम टूट जाए!

लेकिन ज्ञात कंपाइलर्स आपको निम्नलिखित करने की अनुमति देते हैं:

 union un { uint16_t array16[4]; uint32_t array32[2]; } 

तकनीकी रूप से यह अभी भी नियमों का उल्लंघन है। लेकिन सभी ज्ञात मानक इस उपयोग का समर्थन करते हैं।