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


236

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

जवाबों:


252

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

union
{
  int i;
  float f;
} u;

// Convert floating-point bits to integer:
u.f = 3.14159f;
printf("As integer: %08x\n", u.i);

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

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

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 S28 के बजाय केवल 12 बाइट्स का आकार देता है ।


uf की जगह उई होनी चाहिए
अमित सिंह तोमर

1
क्या उदाहरण है जो फ्लोट को पूर्णांक कार्यों में परिवर्तित करता है? मुझे ऐसा नहीं लगता, क्योंकि इंट और फ्लोट को मेमोरी में अलग-अलग फॉर्मेट में स्टोर किया जाता है। क्या आप अपना उदाहरण बता सकते हैं?
spin_eight

3
@spin_eight: यह फ्लोट से इंट में "परिवर्तित" नहीं है। "फ्लोट के द्विआधारी प्रतिनिधित्व को फिर से परिभाषित करना जैसे कि यह एक अंतर था"। आउटपुट 3 नहीं है: ideone.com/MKjwon मुझे यकीन नहीं है कि एडम क्यों हेक्स के रूप में प्रिंट कर रहा है।
एंडोलिथ

@ अदम रोसेनफील्ड मैं वास्तव में रूपांतरण को समझ नहीं पाया, मुझे आउटपुट में पूर्णांक नहीं मिला: p
द बीस्ट

2
मुझे लगता है कि अपरिभाषित व्यवहार के बारे में अस्वीकरण हटा दिया जाना चाहिए। यह वास्तव में, परिभाषित व्यवहार है। C99 मानक के फुटनोट 82 देखें: यदि किसी संघ वस्तु की सामग्री का उपयोग करने के लिए उपयोग किया गया सदस्य समान नहीं है, तो अंतिम बार सदस्य का उपयोग वस्तु में एक मूल्य को संग्रहित करने के लिए किया जाता है, मूल्य के वस्तु प्रतिनिधित्व का उचित भाग फिर से समझा जाता है। 6.2.6 में वर्णित नए प्रकार में एक वस्तु प्रतिनिधित्व (एक प्रक्रिया जिसे कभी-कभी "टाइप पिंगिंग" कहा जाता है)। यह एक जाल प्रतिनिधित्व हो सकता है।
क्रिश्चियन गिबन्स

136

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

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;

3
यहाँ आपका जवाब @Adam Rosenfield के उत्तर के साथ मिलकर सही पूरक जोड़ी बनाते हैं: आप एक संघ के भीतर एक संरचना का उपयोग करते हुए प्रदर्शित करते हैं, और वह एक संघ का उपयोग करके एक संरचना के भीतर प्रदर्शित करता है । यह पता चला है कि मुझे एक ही बार में दोनों की आवश्यकता है: एक एम्बेडेड सिस्टम पर थ्रेड्स के बीच सी में कुछ फैंसी संदेश-गुजरता बहुरूपता को लागू करने के लिए एक संघ के भीतर एक संरचना , और मुझे एहसास नहीं होगा कि मैंने आपके दोनों उत्तरों को एक साथ नहीं देखा था ।
गेब्रियल स्टेपल्स

1
मैं गलत था: यह एक संघ के भीतर एक संरचना के भीतर एक संघ के भीतर है, नेस्टेड को लिखने के लिए छोड़ दिया जैसा कि मैंने लिखा है कि, आंतरिक-सबसे घोंसले से बाहरी-सबसे स्तर तक। मुझे विभिन्न डेटा प्रकारों के मूल्यों की अनुमति देने के लिए आंतरिक-सबसे स्तर पर एक और संघ जोड़ना पड़ा।
गेब्रियल स्टेपल्स

64

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

IIRC, मैंने घटक बिट्स में हार्डवेयर रजिस्टरों को तोड़ने के लिए यूनियनों का उपयोग किया है। तो, आप एक 8-बिट रजिस्टर तक पहुँच सकते हैं (जैसा कि मैंने किया था, दिन में मैंने ऐसा किया ;-) घटक बिट्स में।

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

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;

3
यह एक उत्कृष्ट उदाहरण है! इस बात का एक उदाहरण है कि आप इस तकनीक को एम्बेडेड सॉफ़्टवेयर में कैसे उपयोग कर सकते हैं: edn.com/design/integrated-circuit-design/4394915/…
rzetterberg

34

मैंने इसे कुछ पुस्तकालयों में ऑब्जेक्ट ओरिएंटेड इनहेरिटेंस के प्रतिस्थापन के रूप में देखा है।

उदाहरण के लिए

        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=3e887870d63bd754c6b5ec232948027bbff4dc=hb=b;


33

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

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

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

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


29

हमें बहुत सारे। बस करो grep union /usr/include/*या समान निर्देशिकाओं में। अधिकांश मामलों में unionलपेटा जाता है 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;
}

ठीक वही जो मेरे द्वारा खोजा जा रहा था ! कुछ दीर्घवृत्तीय पैरामीटर को प्रतिस्थापित करने के लिए बहुत उपयोगी :)
निकोलस वोरोन

17

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

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;

"वैरिएबल [b]" एलिमेंट बनाने के लिए, आप उपयोग करेंगे:

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;}) और अन्य प्रकारों को शामिल करने के लिए इसका विस्तार कर सकते हैं ।

मूल आधार यह है कि 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 |       |
       +-------+

क्या make sure you free this laterनिरंतर तत्व से टिप्पणी को हटाया जाना चाहिए ?
ट्रेवर

हां, @ ट्रेवर, हालांकि मुझे विश्वास नहीं हो रहा है कि आप पिछले 4+ वर्षों में इसे देखने वाले पहले व्यक्ति हैं। :-) फिक्स्ड, और इसके लिए धन्यवाद।
पैक्सिडाब्लो

7

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

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

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

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

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

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


5

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

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

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

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

MyUnion में केवल एक int या एक फ़्लोट होगा, जिसके आधार पर आप सबसे हाल ही में सेट होते हैं । तो यह कर:

MYUNION u;
u.MyInt = 10;

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

u.MyFloat = 1.0;

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

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


1
sizeof(int) == sizeof(float)( == 32) आमतौर पर।
निक

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

4

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


4

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

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..
    }
}

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


1
यह कोड काम नहीं करेगा (ज्यादातर बार) यदि निम्न कारणों से 2 डिसिमिलर प्लेटफॉर्म पर डेटा का आदान-प्रदान किया जा रहा है: 1) एंडियननेस अलग हो सकता है। 2) संरचनाओं में पैडिंग।
महोरी

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

1

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

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

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

1

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


1

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

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

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


1

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

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

इसे शिफ्टिंग की आवश्यकता नहीं है इसलिए कोड को पढ़ना आसान है।

दूसरी ओर, मैंने कुछ पुराने C ++ stl कोड देखे जो stl एलोकेटर के लिए यूनियन का उपयोग करते थे। यदि आप रुचि रखते हैं, तो आप sgi stl स्रोत कोड पढ़ सकते हैं । यहाँ इसका एक टुकड़ा है:

union _Obj {
    union _Obj* _M_free_list_link;
    char _M_client_data[1];    /* The client sees this.        */
};

1
आप structअपने आसपास एक समूहीकरण की आवश्यकता नहीं होगी higher/ lower? अभी दोनों को पहले बाइट की ओर ही इशारा करना चाहिए।
मारियो

@ मोरियो आह ठीक है, मैं बस इसे हाथ से लिखता हूं और इसके बारे में भूल जाता हूं, धन्यवाद
म्यू क़ियाओ

1
  • एक फ़ाइल जिसमें विभिन्न रिकॉर्ड प्रकार होते हैं।
  • एक नेटवर्क इंटरफ़ेस जिसमें विभिन्न अनुरोध प्रकार होते हैं।

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

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


क्या आप इन दोनों उदाहरणों की व्याख्या कर सकते हैं। मेरा मतलब है कि ये संघ से कैसे संबंधित हैं
अमित सिंह तोमर

1

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

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];};

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

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

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


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

@ हर्ड्समैन: सी के शुरुआती संस्करणों में, एक संरचनात्मक सदस्य नाम ने एक प्रकार और एक ऑफसेट समझाया। विभिन्न संरचनाओं के दो सदस्यों का एक ही नाम हो सकता है यदि और केवल यदि उनके प्रकार और ऑफसेट मेल खाते हैं। Struct सदस्य हैं fooएक है intके साथ ऑफसेट 8, तो anyPointer->foo = 1234;मतलब था "anyPointer में पता 8 बाइट्स से यह विस्थापित लेते हैं,, और जिसके परिणामस्वरूप पता करने के लिए 1234 मूल्य के एक पूर्णांक की दुकान करते हैं। संकलक है कि क्या जानते हैं या देखभाल की जरूरत नहीं होगी anyPointerपहचान किसी भी प्रकार की संरचना जो fooउसके सदस्यों के बीच सूचीबद्ध थी ।
सुपरकैट

पॉइंटर के साथ आप पॉइंटर की 'उत्पत्ति' की परवाह किए बिना किसी भी एडरेस को डिरेल कर सकते हैं, यह सच है, लेकिन फिर कंपाइलर के सदस्यों और उनके नामों (जैसे कि आपने अपनी पोस्ट में कहा था) की तालिका रखने के लिए कंपाइलर का क्या मतलब है अगर मैं डेटा ला सकता हूं किसी भी संकेतक के साथ किसी विशेष संरचना में किसी सदस्य के पते को जानना? और यदि कंपाइलर को यह पता नहीं है कि anyPointerएक स्ट्रक्चर मेंबर के साथ इंडेंटिफाई होता है, तो कंपाइलर to have a member with the same name only if the type and offset matchedआपके पोस्ट की इन कंडीशन को कैसे चेक करेगा ?
चरवाहे

@ हर्ड्समैन: कंपाइलर संरचना के सदस्यों के नामों की सूची रखेगा क्योंकि इसका सटीक व्यवहार p->fooप्रकार और ऑफसेट पर निर्भर करेगा foo। अनिवार्य रूप से, p->fooशॉर्टहैंड था *(typeOfFoo*)((unsigned char*)p + offsetOfFoo)। आपके उत्तरार्द्ध प्रश्न के लिए, जब एक कंपाइलर एक संरचनात्मक सदस्य परिभाषा का सामना करता है, तो यह आवश्यक है कि या तो उस नाम के साथ कोई सदस्य मौजूद नहीं है, या उस नाम वाले सदस्य के पास एक ही प्रकार और ऑफसेट है; मुझे लगता है कि अगर एक गैर-मिलान संरचना सदस्य परिभाषा मौजूद है, तो स्क्वाक्क्ड होगा, लेकिन मुझे नहीं पता कि यह कैसे त्रुटियों को नियंत्रित करता है।
सुपरकैट

0

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

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

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

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

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

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

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