कोई किसी संघ का उपयोग कब करेगा? क्या यह केवल-सी के दिनों का अवशेष है?


133

मैंने सीखा है लेकिन वास्तव में यूनियनों को नहीं मिलता है। प्रत्येक C या C ++ टेक्स्ट मैं उनके माध्यम से जाता हूं (कभी-कभी गुजरने में), लेकिन वे बहुत कम व्यावहारिक उदाहरण देते हैं कि उन्हें क्यों या कहां उपयोग करना है। आधुनिक (या यहां तक ​​कि विरासत) मामले में यूनियनें कब उपयोगी होंगी? जब आप के साथ काम करने के लिए बहुत सीमित स्थान है, या जब आप एक एपीआई (या कुछ इसी तरह) का विकास कर रहे हैं, और आप अंत उपयोगकर्ता को कई वस्तुओं / प्रकारों के केवल एक ही उदाहरण के लिए बाध्य करना चाहते हैं, तो मेरे केवल दो अनुमान माइक्रोप्रोसेसरों की प्रोग्रामिंग करेंगे। एक बार। क्या ये दोनों अनुमान सही होने के करीब भी हैं?


31
C / C ++ कोई भाषा नहीं है। यूनियन्स C में मध्यम रूप से उपयोगी हैं और C ++ में काफी हद तक बेकार हैं। यह कहना सही होगा कि सी ++ में वे "सी + पर आधारित सी + से अवशेष हैं", लेकिन यह कहने के लिए नहीं कि वे "केवल सी से एक अवशेष" हैं जैसे कि सी ++ सुपरसीट सी
आर .. गिटहब

12
क्या आप इस बारे में विस्तार से बता सकते हैं कि यूनियनों के लिए सी + + का विकल्प क्या है, या वे सी ++ में बेकार क्यों हैं?
रसेल

3
यूनियनों के लिए C ++ का विकल्प वर्ग और वंशानुक्रम है - C में यूनियनें लगभग विशेष रूप से प्रकार-सुरक्षित बहुरूपता के लिए उपयोग की जाती हैं। कुछ कक्षाएं बहुत बेहतर हैं। (देखें सी-स्टाइल बहुरूपता के लिए vz0 का उत्तर)
टोबैडोविज़

6
@R ..: C ++ में संघ अभी भी उपयोगी है। नीचे उत्तर देखें।
माइकल

2
एक ऑपरेटिंग सिस्टम की हिम्मत में, या जैसे, उदाहरण के लिए, एक पैकेज है जो ध्वनि फ़ाइलों को असेंबल / डिस्सेम्बल करता है। ऐसे संदर्भों में उनका उपयोग कई अलग-अलग तरीकों से किया जाता है - डेटा / एंडियन रूपांतरण, निम्न-स्तरीय बहुरूपता, एट अल। हां, एक ही समस्या के अन्य समाधान हैं (मुख्य रूप से सूचक प्रकारों के बीच कास्टिंग), लेकिन यूनियनों अक्सर क्लीनर और बेहतर स्व-दस्तावेजीकरण होते हैं।
हॉट लिक्स

जवाबों:


105

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

struct my_variant_t {
    int type;
    union {
        char char_value;
        short short_value;
        int int_value;
        long long_value;
        float float_value;
        double double_value;
        void* ptr_value;
    };
};

तो आप इसे इस तरह से उपयोग करेंगे:

/* construct a new float variant instance */
void init_float(struct my_variant_t* v, float initial_value) {
    v->type = VAR_FLOAT;
    v->float_value = initial_value;
}

/* Increments the value of the variant by the given int */
void inc_variant_by_int(struct my_variant_t* v, int n) {
    switch (v->type) {
    case VAR_FLOAT:
        v->float_value += n;
        break;

    case VAR_INT:
        v->int_value += n;
        break;
    ...
    }
}

यह वास्तव में एक सुंदर सामान्य मुहावरा है, विशेष रूप से Visual Basic आंतरिक पर।

एक वास्तविक उदाहरण के लिए SDL का SDL_Event यूनियन देखें । ( वास्तविक स्रोत कोड यहाँ )। typeसंघ के शीर्ष पर एक फ़ील्ड है, और प्रत्येक SDL_ * इवेंट संरचना पर एक ही फ़ील्ड दोहराया जाता है। फिर, सही घटना को संभालने के लिए आपको typeफ़ील्ड का मान जाँचना होगा ।

लाभ सरल हैं: अनावश्यक स्मृति का उपयोग किए बिना सभी घटना प्रकारों को संभालने के लिए एक एकल डेटा प्रकार है।


2
महान! उस स्थिति में, मैं अब सोच रहा हूं कि Sdl फ़ंक्शन को सिर्फ क्लास पदानुक्रम के रूप में क्यों लागू नहीं किया गया था। यह है कि यह सी संगत बनाने के लिए और न सिर्फ सी ++?
रसेल

12
@Russel C ++ क्लासेस का उपयोग C प्रोग्राम से नहीं किया जा सकता, लेकिन C स्ट्रक्चर्स / यूनियनों को C ++ से 'एक्सटर्नल "C"' ब्लॉक का उपयोग करके आसानी से प्राप्त किया जा सकता है।
vz0

1
इस प्रकार पैटर्न भी अक्सर, जैसे की परिभाषा प्रोग्रामिंग भाषा दुभाषिए के लिए प्रयोग किया जाता है struct objectमें github.com/petermichaux/bootstrap-scheme/blob/v0.21/scheme.c
एडम Rosenfield

1
बहुत बढ़िया व्याख्या। मुझे हमेशा से पता था कि यूनियनें क्या हैं, लेकिन कभी भी इस बात का वास्तविक कारण नहीं देखा कि कोई भी उनका उपयोग करने के लिए क्यों पागल होगा :) उदाहरण के लिए धन्यवाद।
19

@ Stargazer712, Google की
कोडसर्च

87

मुझे लगता है कि सी ++ यूनियनों बहुत अच्छा है। ऐसा लगता है कि लोग आमतौर पर केवल उपयोग के मामले के बारे में सोचते हैं जहां कोई "उदाहरण के लिए" (उदाहरण के लिए, ऐसा लगता है कि केवल स्मृति को बचाने या संदेहास्पद रूपांतरण करने के लिए कार्य करता है) के मूल्य को बदलना चाहता है।

वास्तव में, यूनियन एक सॉफ्टवेयर इंजीनियरिंग उपकरण के रूप में महान शक्ति के हो सकते हैं, तब भी जब आप किसी भी संघ उदाहरण के मूल्य को कभी नहीं बदलते हैं

केस 1 का प्रयोग करें: गिरगिट

यूनियनों के साथ, आप एक संप्रदाय के तहत कई मनमानी वर्गों को फिर से इकट्ठा कर सकते हैं, जो आधार वर्ग और इसके व्युत्पन्न वर्गों के मामले के साथ समानता के बिना नहीं है। हालाँकि, क्या बदलाव है, जो आप किसी दिए गए यूनियन उदाहरण के साथ कर सकते हैं और नहीं कर सकते हैं:

struct Batman;
struct BaseballBat;

union Bat
{
    Batman brucewayne;
    BaseballBat club;
};

ReturnType1 f(void)
{
    BaseballBat bb = {/* */};
    Bat b;
    b.club = bb;
    // do something with b.club
}

ReturnType2 g(Bat& b)
{
    // do something with b, but how do we know what's inside?
}

Bat returnsBat(void);
ReturnType3 h(void)
{
    Bat b = returnsBat();
    // do something with b, but how do we know what's inside?
}

ऐसा प्रतीत होता है कि प्रोग्रामर को किसी दिए गए यूनियन उदाहरण की सामग्री के प्रकार के बारे में निश्चित होना चाहिए जब वह इसका उपयोग करना चाहता है। यह fऊपर फ़ंक्शन में मामला है । हालाँकि, यदि कोई फ़ंक्शन पास किए गए तर्क के रूप में एक संघ उदाहरण प्राप्त करना था, जैसा कि gऊपर के मामले में है, तो यह नहीं जानता कि इसके साथ क्या करना है। संघ के उदाहरणों को लौटाने वाले फ़ंक्शन पर भी यही लागू होता है, देखें h: कॉलर को कैसे पता चलता है कि उसके अंदर क्या है?

यदि कोई संघ उदाहरण तर्क या रिटर्न मान के रूप में कभी भी पास नहीं होता है, तो यह एक बहुत नीरस जीवन के लिए बाध्य है, उत्साह के स्पाइक्स के साथ जब प्रोग्रामर अपनी सामग्री को बदलने का विकल्प चुनता है:

Batman bm = {/* */};
Baseball bb = {/* */};
Bat b;
b.brucewayne = bm;
// stuff
b.club = bb;

और यह यूनियनों का सबसे (संयुक्त राष्ट्र) लोकप्रिय उपयोग मामला है। एक अन्य उपयोग मामला तब है जब एक संघ उदाहरण कुछ के साथ आता है जो आपको अपना प्रकार बताता है।

मामले 2 का उपयोग करें: "आपसे मिलकर अच्छा लगा, मैं कर रहा हूँ object, से Class"

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

फिर प्रोग्रामर को switchब्रूस वेन को लकड़ी की छड़ी, या कुछ समतुल्य बताने के लिए एक नियंत्रण प्रवाह विवरण लिखना होगा । यह बहुत बुरा नहीं है जब संघ में केवल दो प्रकार की सामग्री होती है, लेकिन जाहिर है, संघ अब कोई पैमाना नहीं है।

केस 3 का उपयोग करें:

आईएसओ सी ++ मानक के लिए एक सिफारिश के लेखकों के रूप में इसे 2008 में वापस रखा गया,

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

और अब, एक उदाहरण, एक यूएमएल वर्ग आरेख के साथ:

कक्षा ए के लिए कई रचनाएँ

सादे अंग्रेजी में स्थिति: कक्षा एक की एक वस्तु कर सकते हैं बी 1 के बीच किसी भी वर्ग की वस्तुओं है, ..., बटालियन, और प्रत्येक प्रकार के सबसे एक, के साथ कम से n एक बहुत बड़ी संख्या होने के नाते, का कहना है कि कम से कम 10।

हम ए की तरह फ़ील्ड (डेटा सदस्य) जोड़ना नहीं चाहते हैं:

private:
    B1 b1;
    .
    .
    .
    Bn bn;

क्योंकि n भिन्न हो सकते हैं (हम मिश्रण में Bx कक्षाएं जोड़ना चाहते हैं), और क्योंकि इससे निर्माणकर्ताओं के साथ गड़बड़ी होगी और क्योंकि A ऑब्जेक्ट में बहुत अधिक जगह होगी।

हम एक निराला कंटेनर इस्तेमाल कर सकते हैं void*की ओर इशारा Bxडाले के साथ वस्तुओं के लिए उन्हें पुनः प्राप्त करने, लेकिन वह fugly और इतने सी शैली है ... लेकिन अधिक महत्वपूर्ण बात यह है कि हम कई गतिशील आवंटित वस्तुओं के जीवन काल का प्रबंधन करने के साथ छोड़ जाएगा।

इसके बजाय, क्या किया जा सकता है:

union Bee
{
    B1 b1;
    .
    .
    .
    Bn bn;
};

enum BeesTypes { TYPE_B1, ..., TYPE_BN };

class A
{
private:
    std::unordered_map<int, Bee> data; // C++11, otherwise use std::map

public:
    Bee get(int); // the implementation is obvious: get from the unordered map
};

फिर, एक संघ उदाहरण की सामग्री प्राप्त करने के लिए data, आप उपयोग करते हैं a.get(TYPE_B2).b2और पसंद करते हैं, जहां aएक वर्ग Aउदाहरण है।

यह सभी अधिक शक्तिशाली है क्योंकि यूनियनों को C ++ 11 में अप्रतिबंधित किया गया है। देखें दस्तावेज़ ऊपर से जुड़ा हुआ या इस लेख जानकारी के लिए।


यह बहुत मददगार था, और उस दूसरे लेख की श्रृंखला बहुत जानकारीपूर्ण थी। धन्यवाद।
एंड्रयू

38

एक उदाहरण एम्बेडेड दायरे में है, जहां रजिस्टर के प्रत्येक बिट का मतलब कुछ अलग हो सकता है। उदाहरण के लिए, 8-बिट पूर्णांक और 8 अलग 1-बिट बिटफ़िल्ड के साथ संरचना का एक संघ आपको या तो एक बिट या पूरे बाइट को बदलने की अनुमति देता है।


7
यह डिवाइस चालकों में भी बहुत आम है। कुछ साल पहले मैंने एक परियोजना के लिए यूनियनों का उपयोग करते हुए बहुत सारे कोड लिखे । यह सामान्य रूप से अनुशंसित नहीं है, और यह कुछ मामलों में संकलक-विशिष्ट हो सकता है, लेकिन यह काम करता है।
थकाला २५'११ को १:५०

11
मैं यह नहीं कहूंगा कि "अनुशंसित नहीं"। अंतःस्थापित स्थान में अक्सर विकल्पों की तुलना में बहुत अधिक क्लीनर और कम त्रुटि-प्रवण होता है, जिसमें आमतौर पर या तो स्पष्ट जातियां और void*s या मुखौटे और बदलाव शामिल होते हैं।
बटा

हे? स्पष्ट जातियों के बहुत सारे? मुझे लगता है जैसे सरल बयान REG |= MASKऔर REG &= ~MASK। यदि यह त्रुटि प्रवण है फिर उन्हें एक में डाल दिया #define SETBITS(reg, mask)और #define CLRBITS(reg, mask)। एक निश्चित क्रम में बिट्स प्राप्त करने के लिए संकलक पर भरोसा न करें ( stackoverflow.com/questions/1490092/… )
माइकल

26

हर्ब सटर ने लगभग छह साल पहले GOTW में लिखा , जोर के साथ :

"लेकिन यह मत सोचो कि यूनियन पहले के समय से केवल एक होल्डओवर हैं। डेटा को ओवरलैप करने की अनुमति देकर अंतरिक्ष को बचाने के लिए यूनियन शायद सबसे उपयोगी हैं, और यह अभी भी C ++ और आज की आधुनिक दुनिया में वांछनीय है । उदाहरण के लिए, कुछ सबसे अधिक। उन्नत सी ++दुनिया में मानक पुस्तकालय कार्यान्वयन अब "छोटी स्ट्रिंग अनुकूलन" को लागू करने के लिए बस इस तकनीक का उपयोग करते हैं, एक महान अनुकूलन विकल्प जो एक स्ट्रिंग ऑब्जेक्ट के अंदर भंडारण को पुन: उपयोग करता है: बड़े तारों के लिए, स्ट्रिंग ऑब्जेक्ट के अंदर अंतरिक्ष सामान्य सूचक को गतिशील रूप से संग्रहीत करता है बफर के आकार की तरह आवंटित बफर और हाउसकीपिंग जानकारी; छोटे तारों के लिए, समान स्थान को सीधे स्ट्रिंग सामग्री को संग्रहीत करने और किसी भी गतिशील मेमोरी आवंटन से पूरी तरह से बचने के लिए पुन: उपयोग किया जाता है। छोटे स्ट्रिंग अनुकूलन के बारे में अधिक जानकारी के लिए (और अन्य स्ट्रिंग अनुकूलन और काफी गहराई में निराशाएँ), देखें ... "।

और एक कम उपयोगी उदाहरण के लिए, एक संघ के माध्यम से लंबे लेकिन अनिर्णीत प्रश्न gcc, सख्त-अलियासिंग और कास्टिंग देखें


23

खैर, एक उदाहरण का उपयोग मैं इस बारे में सोच सकता हूं:

typedef union
{
    struct
    {
        uint8_t a;
        uint8_t b;
        uint8_t c;
        uint8_t d;
    };
    uint32_t x;
} some32bittype;

आप डेटा के उस 32-बिट ब्लॉक के 8-बिट अलग-अलग हिस्सों तक पहुंच सकते हैं; हालाँकि, संभावित रूप से धीरज से काटे जाने की तैयारी करें।

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

उन्होंने कहा, एक तरीका यह भी है कि एंडियन-सेफ:

uint32_t x;
uint8_t a = (x & 0xFF000000) >> 24;

उदाहरण के लिए, चूंकि बाइनरी ऑपरेशन कंपाइलर द्वारा सही एंडियननेस में परिवर्तित हो जाएगा।


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

15

यूनियनों के लिए कुछ उपयोग:

  • एक अज्ञात बाहरी होस्ट को सामान्य एंडियननेस इंटरफ़ेस प्रदान करें।
  • विदेशी सीपीयू आर्किटेक्चर फ्लोटिंग पॉइंट डेटा को मैनिप्युलेट करें, जैसे कि एक नेटवर्क लिंक से VAX G_FLOATS को स्वीकार करना और उन्हें प्रसंस्करण के लिए IEEE 754 लंबे रीयल में परिवर्तित करना ।
  • एक उच्च-स्तरीय प्रकार के लिए सीधी सा मोड़ने वाली पहुँच प्रदान करें।
union {
      unsigned char   byte_v[16];
      long double     ld_v;
 }

इस घोषणा के साथ, हेक्स बाइट मानों को प्रदर्शित करना सरल है long double, घातांक के चिह्न को बदलना, यह निर्धारित करना कि क्या यह एक मूल्य है, या सीपीयू के लिए लंबे डबल अंकगणित को लागू करें जो इसका समर्थन नहीं करता है, आदि।

  • जब फ़ील्ड कुछ मानों पर निर्भर होती है, तो संग्रहण स्थान सहेजना:

    class person {  
        string name;  
    
        char gender;   // M = male, F = female, O = other  
        union {  
            date  vasectomized;  // for males  
            int   pregnancies;   // for females  
        } gender_specific_data;
    }
  • अपने संकलक के साथ उपयोग के लिए फ़ाइलों को शामिल करें। आपको दर्जनों से सैकड़ों उपयोग मिलेंगे union:

    [wally@zenetfedora ~]$ cd /usr/include
    [wally@zenetfedora include]$ grep -w union *
    a.out.h:  union
    argp.h:   parsing options, getopt is called with the union of all the argp
    bfd.h:  union
    bfd.h:  union
    bfd.h:union internal_auxent;
    bfd.h:  (bfd *, struct bfd_symbol *, int, union internal_auxent *);
    bfd.h:  union {
    bfd.h:  /* The value of the symbol.  This really should be a union of a
    bfd.h:  union
    bfd.h:  union
    bfdlink.h:  /* A union of information depending upon the type.  */
    bfdlink.h:  union
    bfdlink.h:       this field.  This field is present in all of the union element
    bfdlink.h:       the union; this structure is a major space user in the
    bfdlink.h:  union
    bfdlink.h:  union
    curses.h:    union
    db_cxx.h:// 4201: nameless struct/union
    elf.h:  union
    elf.h:  union
    elf.h:  union
    elf.h:  union
    elf.h:typedef union
    _G_config.h:typedef union
    gcrypt.h:  union
    gcrypt.h:    union
    gcrypt.h:    union
    gmp-i386.h:  union {
    ieee754.h:union ieee754_float
    ieee754.h:union ieee754_double
    ieee754.h:union ieee854_long_double
    ifaddrs.h:  union
    jpeglib.h:  union {
    ldap.h: union mod_vals_u {
    ncurses.h:    union
    newt.h:    union {
    obstack.h:  union
    pi-file.h:  union {
    resolv.h:   union {
    signal.h:extern int sigqueue (__pid_t __pid, int __sig, __const union sigval __val)
    stdlib.h:/* Lots of hair to allow traditional BSD use of `union wait'
    stdlib.h:  (__extension__ (((union { __typeof(status) __in; int __i; }) \
    stdlib.h:/* This is the type of the argument to `wait'.  The funky union
    stdlib.h:   causes redeclarations with either `int *' or `union wait *' to be
    stdlib.h:typedef union
    stdlib.h:    union wait *__uptr;
    stdlib.h:  } __WAIT_STATUS __attribute__ ((__transparent_union__));
    thread_db.h:  union
    thread_db.h:  union
    tiffio.h:   union {
    wchar.h:  union
    xf86drm.h:typedef union _drmVBlank {

5
Tsk tsk! दो डाउनवोट और कोई स्पष्टीकरण नहीं। यह निराशाजनक है।
wallyk

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

4
मुझे लगता है कि आपको "कास्टेड" या "गर्भधारण" संघ के लिए चढ़ाव मिला है। यह थोड़ा बीमार है।
एकाल्टर

2
हाँ, मुझे लगता है कि यह एक काला दिन था।
वैलीक

14

बाइट-स्तर (निम्न स्तर) डेटा के साथ काम करते समय यूनियन उपयोगी होते हैं।

मेरे हाल के उपयोग में से एक आईपी एड्रेस मॉडलिंग पर था जो नीचे जैसा दिखता है:

// Composite structure for IP address storage
union
{
    // IPv4 @ 32-bit identifier
    // Padded 12-bytes for IPv6 compatibility
    union
    {
        struct
        {
            unsigned char _reserved[12];
            unsigned char _IpBytes[4];
        } _Raw;

        struct
        {
            unsigned char _reserved[12];
            unsigned char _o1;
            unsigned char _o2;
            unsigned char _o3;
            unsigned char _o4;    
        } _Octet;    
    } _IPv4;

    // IPv6 @ 128-bit identifier
    // Next generation internet addressing
    union
    {
        struct
        {
            unsigned char _IpBytes[16];
        } _Raw;

        struct
        {
            unsigned short _w1;
            unsigned short _w2;
            unsigned short _w3;
            unsigned short _w4;
            unsigned short _w5;
            unsigned short _w6;
            unsigned short _w7;
            unsigned short _w8;   
        } _Word;
    } _IPv6;
} _IP;

7
हालांकि, यह ध्यान रखें कि कच्चे माल तक पहुँच जैसे कि मानक नहीं है, और सभी कंपाइलरों के साथ अपेक्षित रूप से काम नहीं कर सकता है।
ओपन स्कूल

3
इसके अलावा, इस तरह से इस्तेमाल किया जाना बहुत आम है जो कि संरेखण की गारंटी नहीं देता है, जो अपरिभाषित व्यवहार है।
मूविंग डक

10

एक उदाहरण जब मैंने एक संघ का उपयोग किया है:

class Vector
{
        union 
        {
            double _coord[3];
            struct 
            {
                double _x;
                double _y; 
                double _z;
            };

        };
...
}

यह मुझे एक सरणी या तत्वों के रूप में अपने डेटा तक पहुंचने की अनुमति देता है।

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

   union {   // dimension from left to right   // union for the left to right dimension
        uint32_t            m_width;
        uint32_t            m_sizeX;
        uint32_t            m_columns;
    };

    union {   // dimension from top to bottom   // union for the top to bottom dimension
        uint32_t            m_height;
        uint32_t            m_sizeY;
        uint32_t            m_rows;
    };

12
ध्यान दें, यद्यपि यह समाधान अधिकतर अवलोकन योग्य प्लेटफार्मों पर काम करता है, __x, _y, _z पर मान सेट करता है और _coord तक पहुँचना एक अपरिभाषित व्यवहार है। यूनियनों का मुख्य उद्देश्य अंतरिक्ष संरक्षण है। आपको ठीक उसी संघ तत्व तक पहुंचना चाहिए जिसे आपने पहले सेट किया था।

1
यह है कि मैं इसे भी उपयोग करते हैं, मैं भी एक std :: सरणी forr coards का उपयोग करें, और कुछ static_asserts
विक्टर सेहर

1
यह कोड सख्त अलियासिंग नियमों का उल्लंघन करता है और इसकी सिफारिश नहीं की जानी चाहिए।
वाल्टर

क्या संघ में सुधार करने का कोई तरीका शायद ऐसा है कि ऐसा करना विश्वसनीय होगा?
एंड्रयू

8

यूनियन सी में बहुरूपता प्रदान करते हैं।


18
मैंने सोचा void*कि ^ ^

2
@ user166390 बहुरूपता एक ही इंटरफ़ेस का उपयोग कई प्रकार के हेरफेर करने के लिए कर रहा है; शून्य * का कोई इंटरफ़ेस नहीं है।
ऐलिस

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

7

संघ का एक शानदार उपयोग मेमोरी संरेखण है, जो मुझे पीसीएल (प्वाइंट क्लाउड लाइब्रेरी) स्रोत कोड में मिला है। एपीआई में एकल डेटा संरचना दो आर्किटेक्चर को लक्षित कर सकती है: एसएसई समर्थन के साथ सीपीयू और साथ ही एसएसई समर्थन के बिना सीपीयू। उदाहरण के लिए: पॉइंटएक्सवाईजेड के लिए डेटा संरचना है

typedef union
{
  float data[4];
  struct
  {
    float x;
    float y;
    float z;
  };
} PointXYZ;

3 फ़्लोट्स SSE संरेखण के लिए एक अतिरिक्त फ़्लोट के साथ गद्देदार होते हैं। के लिए

PointXYZ point;

उपयोगकर्ता कह सकते हैं कि बिंदु तक पहुँचने के लिए बिंदु.data [0] या point.x (SSE समर्थन पर निर्भर करता है) x समन्वय कर सकता है। इसी तरह के बेहतर उपयोग विवरण निम्नलिखित लिंक पर हैं: पीसीएल प्रलेखन प्वाइंट प्रकार


7

unionकीवर्ड, जबकि अभी भी सी में प्रयोग किया जाता ++ 03 1 , ज्यादातर सी दिनों के अवशेष है। सबसे चमकदार मुद्दा यह है कि यह केवल POD 1 के साथ काम करता है ।

हालाँकि, संघ का विचार अभी भी मौजूद है, और वास्तव में बूस्ट पुस्तकालयों में एक संघ जैसा वर्ग है:

boost::variant<std::string, Foo, Bar>

union(यदि सभी नहीं है) और जोड़े जाने के अधिकांश लाभ हैं:

  • गैर-पीओडी प्रकारों का सही उपयोग करने की क्षमता
  • स्थिर प्रकार की सुरक्षा

व्यवहार में, यह प्रदर्शन किया गया है कि यह का एक संयोजन के बराबर था union+ enum(जबकि, और बेंचमार्क है कि यह जितनी जल्दी हो गया था boost::anyके दायरे से अधिक है dynamic_cast, के बाद से यह RTTI उपयोग करता है)।

1 यूनियनों को C ++ 11 ( अप्रतिबंधित यूनियनों ) में अपग्रेड किया गया था , और अब इसमें डिस्ट्रक्टर्स के साथ ऑब्जेक्ट्स हो सकते हैं, हालांकि उपयोगकर्ता को डिस्ट्रक्टर को मैन्युअल रूप से इनवॉइस करना होगा (वर्तमान में सक्रिय यूनियन मेंबर पर)। अभी भी वेरिएंट का उपयोग करना बहुत आसान है।


यह c ++ के अधिक हाल के संस्करणों में सच नहीं है। उदाहरण के लिए, जर्सला का उत्तर देखें।
एंड्रयू

@ संकेत: मैंने यह उल्लेख करने के लिए उत्तर दिया कि C ++ 11, अप्रतिबंधित यूनियनों के साथ, विध्वंसक के साथ प्रकारों को संघ में संग्रहीत करने की अनुमति देता है। मैं अभी भी अपने रुख के साथ खड़ा हूं कि आप वास्तव में टैग किए गए यूनियनों का उपयोग करने से बहुत बेहतर हैं जैसे कि boost::variantअपने दम पर यूनियनों का उपयोग करने का प्रयास करना। यूनियनों के आस-पास बहुत अधिक अपरिभाषित व्यवहार है कि आपके सही होने की संभावना कम है।
मैथ्यू एम।

3

से यूनियनों पर विकिपीडिया लेख :

एक संघ की प्राथमिक उपयोगिता अंतरिक्ष के संरक्षण के लिए है , क्योंकि यह एक ही स्थान में कई अलग-अलग प्रकारों को संग्रहीत करने का एक तरीका प्रदान करता है। यूनियनें क्रूड पॉलीमॉर्फिज़्म भी प्रदान करती हैं । हालांकि, प्रकार की कोई जाँच नहीं है, इसलिए यह सुनिश्चित करने के लिए प्रोग्रामर पर निर्भर है कि अलग-अलग संदर्भों में उचित फ़ील्ड्स को एक्सेस किया जाए। संघ चर का प्रासंगिक क्षेत्र आमतौर पर अन्य चर की स्थिति से निर्धारित होता है, संभवतः एक संलग्न संरचना में।

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


2

सी के शुरुआती दिनों में (जैसे 1974 में प्रलेखित), सभी संरचनाओं ने अपने सदस्यों के लिए एक सामान्य नाम स्थान साझा किया। प्रत्येक सदस्य का नाम एक प्रकार और एक ऑफसेट के साथ जुड़ा हुआ था; अगर "wd_woozle" ऑफसेट 12 पर एक "int" था, तो pकिसी भी संरचना प्रकार का एक संकेतक दिया गया , p->wd_woozleइसके बराबर होगा *(int*)(((char*)p)+12)। भाषा की आवश्यकता है कि सभी संरचनाओं के सभी प्रकार के सदस्यों के पास अद्वितीय नाम हैं सिवाय इसके कि यह स्पष्ट रूप से उन मामलों में सदस्य नामों के पुन: उपयोग की अनुमति देता है जहां हर संरचना जहां उनका उपयोग किया गया था उन्हें एक सामान्य प्रारंभिक अनुक्रम के रूप में माना जाता है।

यह तथ्य कि संरचना के प्रकारों का उपयोग किया जा सकता है, संरचनाओं को व्यवहार करना संभव है, क्योंकि वे अतिव्यापी क्षेत्र होते थे। उदाहरण के लिए, दी गई परिभाषाएँ:

struct float1 { float f0;};
struct byte4  { char b0,b1,b2,b3; }; /* Unsigned didn't exist yet */

कोड "फ्लोट 1" प्रकार की संरचना की घोषणा कर सकता है और फिर उसमें व्यक्तिगत बाइट्स तक पहुंचने के लिए "सदस्य" बी 0 ... बी 3 का उपयोग कर सकता है। जब भाषा को बदल दिया गया था ताकि प्रत्येक संरचना को अपने सदस्यों के लिए एक अलग नामस्थान प्राप्त हो जाए, तो कोड जो कई तरीकों से चीजों को एक्सेस करने की क्षमता पर निर्भर करता है, टूट जाएगा। विभिन्न संरचना प्रकारों के लिए अलग-अलग नामस्थानों को अलग करने के लिए यह आवश्यक है कि इसे समायोजित करने के लिए इस तरह के कोड को बदला जाए, लेकिन इस तरह की तकनीकों का मूल्य भाषा का विस्तार करने के लिए समर्थन जारी रखने के लिए पर्याप्त था।

कोड है जो एक के भीतर भंडारण उपयोग करने की क्षमता का दोहन करने के लिखा गया था struct float1जैसे कि यह एक थे struct byte4एक घोषणा जोड़कर नई भाषा में काम करने के लिए किया जा सकता है: union f1b4 { struct float1 ff; struct byte4 bb; };प्रकार के रूप में घोषित वस्तुओं union f1b4;के बजाय struct float1, और करने के लिए पहुंच की जगह f0, b0, b1, आदि । के साथ ff.f0, bb.b0, bb.b1, आदि जबकि वहाँ बेहतर तरीके ऐसे कोड का समर्थन किया जा सकता था कर रहे हैं, unionदृष्टिकोण कम से कम कुछ हद तक व्यावहारिक, कम से कम अलियासिंग नियमों का C89 युग व्याख्याओं के साथ किया गया था।


1

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

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


1

एक हाल ही में बढ़ावा, पहले से ही ऊंचा, संघ के महत्व को सख्त अलियासिंग नियम द्वारा दिया गया हैसी के मानक के हाल के संस्करण में शुरू है।

आप C मानक का उल्लंघन किए बिना यूनियनों का उपयोग टाइप-पिंगिंग के लिए कर सकते हैं ।
इस कार्यक्रम में अनिर्दिष्ट व्यवहार है (क्योंकि मैंने यह मान लिया है floatऔर unsigned intइसकी लंबाई समान है) लेकिन अपरिभाषित व्यवहार नहीं है ( यहां देखें )।

#include <stdio.h> 

union float_uint
{
    float f;
    unsigned int ui;
};

int main()
{
    float v = 241;
    union float_uint fui = {.f = v};

    //May trigger UNSPECIFIED BEHAVIOR but not UNDEFINED BEHAVIOR 
    printf("Your IEEE 754 float sir: %08x\n", fui.ui);

    //This is UNDEFINED BEHAVIOR as it violates the Strict Aliasing Rule
    unsigned int* pp = (unsigned int*) &v;

    printf("Your IEEE 754 float, again, sir: %08x\n", *pp);

    return 0;
}

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

1

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

struct Number{
enum NumType{int32, float, double, complex}; NumType num_t;
union{int ival; float fval; double dval; ComplexNumber cmplx_val}
}

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

struct NumberBase
{
virtual Add(NumberBase n);
...
}
struct NumberInt: Number
{
//implement methods assuming Number's union contains int
NumberBase Add(NumberBase n);
...
}
struct NumberDouble: Number
{
 //implement methods assuming Number's union contains double
 NumberBase Add(NumberBase n);
 ...
}
//e.t.c. for all number types/or use templates
struct Number: NumberBase{
 union{int ival; float fval; double dval; ComplexNumber cmplx_val;}
 NumberBase* num_t;
 Set(int a)
 {
 ival=a;
  //still kind of hack, hope it works because derived classes of   Number    dont add any fields
 num_t = static_cast<NumberInt>(this);
 }
}

तो आप स्विच (प्रकार) के साथ प्रकार की जांच के बजाय बहुरूपता का उपयोग कर सकते हैं - मेमोरी-कुशल कार्यान्वयन (छोटी वस्तुओं का कोई गतिशील आवंटन) के साथ - यदि आपको इसकी आवश्यकता है, तो निश्चित रूप से।


गतिशील भाषा बनाते समय यह उपयोगी हो सकता है। मुझे लगता है कि यह समस्या हल हो जाएगी उस संशोधन को लागू करने के बिना मास में अज्ञात प्रकार के एक चर को संशोधित कर रहा है। मैक्रों इसके लिए भयावह हैं और गतिरोध लगभग असंभव है।
एंड्रयू

0

से http://cplus.about.com/od/learningc/ss/lowlevel_9.htm :

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

union intptr {   int i;   int * p; }; 
union intptr x; x.i = 1000; 
/* puts 90 at location 1000 */ 
*(x.p)=90; 

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

struct head {   int id;   int response;   int size; }; struct msgstring50 {    struct head fixed;    char message[50]; } struct

संरचना msgstring80 {संरचना प्रमुख तय; चार संदेश [80]; }
स्ट्रक्चर मेसिंट 10 {स्ट्रक्चर हेड फिक्स्ड; int संदेश [10]; } स्ट्रक्चर मेसक {स्ट्रक्चर हेड फिक्स्ड; इंट ओके; } यूनियन
मेसगेटाइप { स्ट्रक्चर मेसस्ट्रिंग 50 एम 50; संरचना msgstring80 m80; संदेश संदेश i10; संरचना मेसक एकक; }

व्यवहार में, हालांकि यूनियनों का आकार समान है, यह केवल सार्थक डेटा भेजने के लिए समझ में आता है और अंतरिक्ष को बर्बाद नहीं करता है। एक msgack आकार में सिर्फ 16 बाइट्स है जबकि एक msgstring80 92 बाइट्स है। इसलिए जब एक मेसैगेटाइप वैरिएबल को इनिशियलाइज़ किया जाता है, तो इसका साइज़ फील्ड सेट होता है, जिसके अनुसार यह होता है। यह तब बाइट्स की सही संख्या को स्थानांतरित करने के लिए अन्य कार्यों द्वारा उपयोग किया जा सकता है।


0

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

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

union u_tag {
     int ival;
     float fval;
     char  *sval;
} u;

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

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