2013-03-27 3 views
7

मैं O'Reilly की प्रैक्टिकल सी प्रोग्रामिंग पुस्तक के माध्यम से जा रहा हूं, और सी प्रोग्रामिंग भाषा पर K & आर पुस्तक पढ़ रहा हूं, और मुझे वास्तव में यूनियनों के पीछे अवधारणा को समझने में परेशानी हो रही है।सी में यूनियनों के पीछे क्या बिंदु है?

वे सबसे बड़े डेटा प्रकार का आकार लेते हैं जो उन्हें बनाता है ... और सबसे हाल ही में असाइन किया गया एक बाकी को ओवरराइट करता है ... लेकिन क्यों आवश्यकतानुसार उपयोग/मुक्त स्मृति का उपयोग नहीं करते?

पुस्तक का उल्लेख है कि इसका संचार में उपयोग किया जाता है, जहां आपको एक ही आकार के झंडे सेट करने की आवश्यकता होती है; और एक गूढ़ वेबसाइट पर, यह अजीब आकार के स्मृति भाग को खत्म कर सकता है ... लेकिन क्या यह आधुनिक, गैर-एम्बेडेड मेमोरी स्पेस में किसी भी उपयोग का है?

क्या आप इसके साथ कुछ सीपीआई रजिस्ट्रार कर सकते हैं? क्या यह प्रोग्रामिंग के पहले युग से बस एक पकड़ है? या यह कुख्यात गोटो की तरह करता है, फिर भी कुछ शक्तिशाली उपयोग (संभवतः तंग स्मृति रिक्त स्थान में) है जो इसे चारों ओर रखने लायक बनाता है?

+1

[टाइप punning] पर एक नजर डालें (http://en.wikipedia.org/wiki/Type_punning)। – Mysticial

+0

यह उन परिस्थितियों में उपयोगी हो सकता है जहां आपको पॉइंटर हैक्स का उपयोग किए बिना किसी संरचना को इसके बाइनरी मानों (जैसे एक char []) में परिवर्तित करने की आवश्यकता होती है। –

+0

[सी/सी ++ का संभावित डुप्लिकेट: जब कोई संघ का उपयोग करेगा? क्या यह मूल रूप से केवल सी से अवशेष है?] (Http: // stackoverflow।कॉम/प्रश्न/4788 9 65/सीसी-कब-कभी-किसी भी-उपयोग-ए-यूनियन-यह-मूल रूप से-एक-अवशेष-से-द-सी-केवल) –

उत्तर

5

ठीक है, आपने लगभग अपने प्रश्न का उत्तर दिया: मेमोरी। दिनों में वापस स्मृति कम थी, और यहां तक ​​कि कुछ kbytes को भी सहेजना उपयोगी रहा है।

लेकिन आज भी ऐसे परिदृश्य हैं जहां यूनियन उपयोगी होंगे। उदाहरण के लिए, यदि आप किसी प्रकार का variant डेटाटाइप लागू करना चाहते हैं। ऐसा करने का सबसे अच्छा तरीका एक संघ का उपयोग कर रहा है।

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

यदि आप क्लासिक struct का उपयोग करते हैं, तो यह 8 बाइट लंबा होगा (कम से कम, यदि आप दुर्भाग्यपूर्ण हैं तो बाइट भर रहे हैं)। union का उपयोग करके यह केवल 4 बाइट्स है। तो आप 50% मेमोरी को सहेज रहे हैं, जो एक उदाहरण के लिए बहुत कुछ नहीं है, लेकिन इनमें से एक लाख होने की कल्पना करें।

जबकि आप एक संघ कास्टिंग या सबक्लासिंग करके समान चीजें प्राप्त कर सकते हैं, यह अभी भी ऐसा करने का सबसे आसान तरीका है।

1

यूनियनों का एक उपयोग दो चरों पर एक ही स्थान पर कब्जा कर रहा है, और संरचना में एक दूसरा चर तय करता है कि आप किस डेटा प्रकार को इसे पढ़ना चाहते हैं।

उदा। आप एक बुलियन 'isDouble' हो सकता है, और एक संघ 'डबलऑरलांग' जिसमें दोहरा और लंबा दोनों हो। यदि दोगुना == सच है तो यूनियन को दोहरी के रूप में समझें और इसे लंबे समय तक समझें।

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

स्मृति की इतनी सस्ती होने के बाद आपको वास्तव में आजकल इसकी आवश्यकता नहीं है, लेकिन एम्बेडेड सिस्टम में इसका उपयोग होता है।

+1

यहां तक ​​कि आधुनिक मशीनों में भी रैम के बहुत सारे गीगाबाइट्स के साथ आपके परिदृश्य के आधार पर बचत स्मृति को नुकसान नहीं पहुंचाएगा, उदाहरण के लिए डिस्क पर कुछ सहेजते समय, किसी नेटवर्क पर कुछ भेजते समय या बस अपने डेटासेट की संख्या के आधार पर। – Mario

+1

@ मारियो सहमत हुए। तर्क यह है कि स्मृति सस्ता है और आपको संरचना आकार के बारे में परवाह करने की आवश्यकता नहीं है हमेशा मुझे आलसी डिजाइन की गंध करता है। मान लें कि आप स्मृति में एक सौ मिलियन रिकॉर्ड स्टोर करना चाहते हैं, और रिकॉर्ड में 32 अलग-अलग बूलियन झंडे हैं। क्या आप 32 बूलियन, या 32-बिट XOR'd पूर्णांक का उपयोग करते हैं। पैडिंग को खराब करना, यह लगभग 3 जीबी का अंतर है। – Anthony

0

विंडोज एपीआई यूनियनों का उपयोग बहुत अधिक करता है। LARGE_INTEGER ऐसे उपयोग का एक उदाहरण है। असल में, यदि कंपाइलर 64-बिट पूर्णांक का समर्थन करता है, तो QuadPart सदस्य का उपयोग करें; अन्यथा, कम DWORD और उच्च DWORD मैन्युअल रूप से सेट करें।

0

यह वास्तव में एक पकड़ नहीं है, क्योंकि सी भाषा 1 9 72 में बनाई गई थी, जब स्मृति एक वास्तविक चिंता थी।

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

ऐसे में, जब सी का उपयोग करना चुनते हैं, तो भी आप इसके लाभों का लाभ उठाना चाहते हैं, जिसमें मेमोरी-स्पेस दक्षता शामिल है। जिसके लिए, संघ बहुत अच्छी तरह से काम करता है; आपको कुछ प्रकार की सुरक्षा की अनुमति मिलती है, जबकि उपलब्ध सबसे छोटी मेमोरी पैर प्रिंट लागू होती है।

+0

असल में, सी की समीक्षा करने के लिए मेरा कारण, फिर सी ++, फिर सी ++ में टेम्पलेटिंग, फिर सीएलआर, फिर सी ++/सीएलआई है क्योंकि मैं नेट सूची/शब्दकोश के लिए 64-बिट (या उच्चतर) इंडेक्स अपग्रेड बनाने की कोशिश कर रहा हूं कक्षाएं और संबंधित कक्षाएं/नामस्थान। मेरे पास खरोंच करने के लिए खुजली है, इसलिए मैं सिर्फ 'ठीक' करने जा रहा हूं जिसे मैं यहां टूटा हुआ मानता हूं। – user978122

0

एक जगह जहां मैंने इसे देखा है, डूम 3/आईडीटेक 4 Fast Inverse Square Root कार्यान्वयन में है।

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

float y = 2.0f; 

// treat the bits of y as an integer 
long i = * (long *) &y; 

// do some stuff with i 

// treat the bits of i as a float 
y = * (float *) &i; 

original source on GitHub

इस कोड को एक चल बिन्दु संख्या y का पता लगता है, एक सूचक के लिए यह एक लंबा करने के लिए डाले (यानी, क्वैक दिनों में 32 बिट पूर्णांक), और इसे i में खराब कर देता है। फिर यह कुछ अविश्वसनीय रूप से विचित्र बिट-ट्विडलिंग सामान, और रिवर्स करता है।

इस तरह से ऐसा करने के दो नुकसान हैं। एक यह है कि एक मजबूत , और पीछे की तरफ जाने के बजाय, स्मृति से पढ़ने के लिए y के मूल्य को नियंत्रित करने के लिए, कास्ट, डीरेंसेंस प्रक्रिया को मजबूत किया गया है। क्वैक-युग कंप्यूटर पर, हालांकि, फ्लोटिंग पॉइंट और इंटीजर रजिस्ट्रार पूरी तरह से अलग थे, इसलिए आपको इस प्रतिबंध से निपटने के लिए मेमोरी को वापस धक्का देना पड़ा।

दूसरी बात यह है कि, कम से कम सी ++ में, इस तरह के कास्टिंग करने पर इस तरह के कास्टिंग करने पर वूडू की मात्रा में काम करने पर भी गहराई से डूब जाता है। मुझे यकीन है कि और अधिक आकर्षक तर्क हैं, हालांकि मुझे यकीन नहीं है कि वे क्या हैं :)

तो, डूम 3 में, आईडी में उनके नए कार्यान्वयन में निम्नलिखित बिट शामिल था (जो बिट ट्विडलिंग के एक अलग सेट का उपयोग करता है, लेकिन एक समान विचार):

union _flint { 
     dword     i; 
     float     f; 
}; 

... 
union _flint seed; 
seed.i = /* look up some tables to get this */; 
double r = seed.f; // <- access the bits of seed.i as a floating point number 

original source on GitHub

सैद्धांतिक रूप से, एक SSE2 मशीन पर, यह एक एकल रजिस्टर के माध्यम से पहुँचा जा सकता है; मुझे अभ्यास में यकीन नहीं है कि कोई संकलक ऐसा करेगा या नहीं। पहले के क्वैक संस्करण में कास्टिंग गेम की तुलना में यह मेरी राय में कुछ हद तक क्लीनर कोड है।


- अनदेखी "पर्याप्त रूप से उन्नत संकलक" तर्कों

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