2013-07-12 9 views
10

सी ++ 11 में धारा 9.6/3 असामान्य रूप से स्पष्ट है: "एक गैर-कॉन्स्ट संदर्भ थोड़ा-सा क्षेत्र तक सीमित नहीं होगा।" इस निषेध के पीछे प्रेरणा क्या है?बिटफील्ड के लिए गैर-कॉन्स्ट संदर्भ क्यों प्रतिबंधित हैं?

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

struct IPv4Header { 
    std::uint32_t version:4,   // assumes the IPv4 Wikipedia entry is correct 
       IHL:4, 
       DSCP:6, 
       ECN:2, 
       totalLength:16; 
}; 

मैं यह क्यों नहीं कह सकता?

IPv4Header h; 

auto& ecn = h.ECN; 

मैं अंतर्निहित कोड वास्तव में पूरे std::uint32_t कि बिट्स मैं में दिलचस्पी रखता हूँ में शामिल करने के लिए बाध्य करने के लिए उम्मीद थी, और मैं उम्मीद थी पढ़ने और लिखने के संचालन उचित मास्किंग करने के लिए कोड उत्पन्न करने के लिए। नतीजा बड़ा और धीमा हो सकता है, लेकिन ऐसा लगता है कि इसे काम करना चाहिए। स्टैंडर्ड इस तरह के अनुरूप होगा का कहना है कि const bitfields काम (फिर 9.6/3 से) के लिए संदर्भ:

हैं प्रकार स्थिरांक टी & के संदर्भ के लिए प्रारंभकर्ता एक lvalue कि थोड़ा के लिए संदर्भित करता है -फील्ड, संदर्भ पर प्रारंभिक अस्थायी के लिए बाध्य है बिट-फ़ील्ड का मान रखें; संदर्भ सीधे बिट-फ़ील्ड से बाध्य नहीं है।

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

मैं स्पष्ट रूप से कुछ याद कर रहा हूं। यह क्या है?

उत्तर

7

गैर-कॉन्स संदर्भों को उसी कारण के लिए बिट-फ़ील्ड से बाध्य नहीं किया जा सकता है पॉइंटर्स बिट-फ़ील्ड को इंगित नहीं कर सकते हैं।

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

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

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

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

+0

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

9

आप एक ही कारण के लिए एक bitfield करने के लिए एक गैर const संदर्भ नहीं ले आप & के साथ अपने पते के नहीं ले जा सकते कर सकते हैं: अपने वास्तविक पते जरूरी char को मेल नहीं किया गया है, जो definitionally स्मृति की सबसे छोटी इकाई है पता सी ++ अमूर्त मशीन में। आप const इसका संदर्भ ले सकते हैं क्योंकि संकलक प्रति प्रतिलिपि के लिए निशुल्क है, क्योंकि इसे उत्परिवर्तित नहीं किया जाएगा।

अलग संकलन के मुद्दे पर विचार करें। const uint32_t& लेने वाले फ़ंक्शन को const uint32_t& पर संचालित करने के लिए एक ही कोड का उपयोग करने की आवश्यकता है। यदि सामान्य मानों और बिटफील्ड मानों के लिए अलग-अलग लेखन व्यवहार की आवश्यकता होती है, तो प्रकार फ़ंक्शन के लिए सही ढंग से काम करने के लिए पर्याप्त जानकारी को एन्कोड नहीं करता है।

+0

यह वास्तव में प्रश्न का उत्तर नहीं देता है, आईएमओ। बिट -फील्ड वाले शब्द से गैर-'कॉन्स्ट' संदर्भ क्यों नहीं हो सकता है, फिर, लिखने पर, केवल बिटफील्ड में बिट्स को संशोधित करने के लिए आवश्यक मास्किंग निष्पादित करें? यह संभवतः तब होता है जब बिटफील्ड सीधे संशोधित होता है, नहीं? – KnowItAllWannabe

+1

आखिरी बिट गलत है। एक कॉन्स संदर्भ का अर्थ मान के बारे में कुछ भी नहीं है या उत्परिवर्तित नहीं किया जा रहा है। यह केवल * उस * संदर्भ के माध्यम से उत्परिवर्तन रोकता है। –

+1

@AndreyT वह अभी भी उस शब्द को और अधिक सही नहीं बनाता है। संकलक इसे कॉपी करने के लिए स्वतंत्र नहीं है क्योंकि इसे उत्परिवर्तित नहीं किया जाएगा। यहां कोई कारण नहीं है। संकलक इसे * डीक्री * द्वारा कॉपी करने के लिए स्वतंत्र है। यह बिटफील्ड की व्यवहार्यता के कारण नहीं है, ऐसा इसलिए है क्योंकि यह लिखा गया है। असल में, यह वास्तव में * मुफ्त * की प्रतिलिपि बनाने के लिए नहीं है, इसे * कॉपी करने के लिए * आवश्यक है। –

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