2010-01-24 5 views
13

मैं इस फैशन में एक बाइट में कुछ बिट्स पैक करने के लिए की जरूरत है:सी/सी ++ बिटफील्ड बनाम बिटवाई ऑपरेटर बिट्स को सिंगल आउट करने के लिए, जो तेज, बेहतर, अधिक पोर्टेबल है?

struct 
{ 
    char bit0: 1; 
    char bit1: 1; 
} a; 

if(a.bit1) /* etc */ 

या:

if(a & 0x2) /* etc */ 

स्रोत कोड स्पष्टता से यह मेरे लिए बहुत स्पष्ट है कि bitfields neater हैं। लेकिन कौन सा विकल्प तेज़ है? मुझे पता है कि गति अंतर बहुत अधिक नहीं होगा, लेकिन जैसा कि मैं उनमें से किसी का उपयोग कर सकता हूं, अगर कोई तेज़, बेहतर है।
दूसरी तरफ, मैंने पढ़ा है कि प्लेटफॉर्म पर उसी क्रम में बिट्स की व्यवस्था करने की गारंटी नहीं है, और मैं चाहता हूं कि मेरा कोड पोर्टेबल हो।

नोट्स: यदि आप 'प्रोफ़ाइल' का उत्तर देने की योजना बना रहे हैं, तो मैं करूँगा, लेकिन जैसा कि मैं आलसी हूं, अगर किसी के पास पहले से ही जवाब है, तो बेहतर होगा।
कोड गलत हो सकता है, यदि आप चाहें तो मुझे सही कर सकते हैं, लेकिन याद रखें कि इस प्रश्न का क्या बिंदु है और कृपया इसे आजमाएं और जवाब दें।

+0

आपको http://stackoverflow.com/questions/1044654/bitfield-manipulation-in-c में रुचि हो सकती है। कम से कम एक और समान प्रश्न है जिस पर मुझे टिप्पणी याद है (यह ऐसा नहीं लगता है)। –

+0

बिटफील्ड: आप बाहर हैं! सभी को धन्यवाद। – Petruza

+0

वाह। हमने यहां एक मूल्यवान सबक सिखाया। –

उत्तर

6

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

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

अकेले नहीं, विभिन्न प्लेटफार्मों के लिए कंपाइलर्स के पास पैडिंग का अपना तरीका होगा, प्रोसेसर के लिए बिटफील्ड को संरेखित करना जहां संकलक चालू है। और इसके अलावा, प्रोसेसर की अंतहीनता के बारे में क्या?

जादू बुलेट के रूप में कभी भी बिटफील्ड पर भरोसा न करें। यदि आप प्रोसेसर के लिए गति चाहते हैं और इसे ठीक किया जाएगा, यानी पोर्टिंग का कोई इरादा नहीं है, तो बिटफील्ड का उपयोग करने में संकोच न करें। आप दोनों नहीं हो सकता!

+0

+1: यह सिर्फ इतना नहीं है कि आपके पास पोर्टिंग का कोई इरादा नहीं है, यह है कि आपके पास एक प्रोसेसर पर स्मृति के बजाए किसी भी संदर्भ में चर के पूर्ण सामग्री को पूर्णांक (बनाम व्यक्तिगत बिट्स) के रूप में उपयोग करने का कोई इरादा नहीं है। यदि आप डिस्क पर, नेटवर्क पर, या कुछ एम्बेडेड सिस्टम परिधीय के लिए बिटफील्ड संरचना का पूर्णांक मान भेजते हैं, तो आप बेहतर सुनिश्चित करेंगे कि संकलक बिटफ़ील्ड को उचित क्रम में रखता है। –

+6

मैन्युअल रूप से परिभाषित लोगों पर बिल्ट-इन बिटफील्ड का उपयोग करने का तरीका समझाने की देखभाल अधिक पोर्टेबल है? मैं इस पर विश्वास कर सकता हूं कि यदि आप स्ट्रक्चर के मेमोरी लेआउट पर बहुत ही निश्चित तरीके से सेट कर रहे हैं, लेकिन यदि आप सब कुछ अंतर्निहित वाक्यविन्यास के माध्यम से प्रत्येक फ़ील्ड तक पहुंचते हैं, तो मैं किसी भी पोर्टेबिलिटी समस्याओं को देखने में विफल रहता हूं। –

+0

अभिभावक गलत है, यह एक CPU पोर्टेबिलिटी समस्या नहीं है, यह एक कंपाइलर पोर्टेबिलिटी समस्या है। प्रत्येक कंपाइलर बिटकफील्ड को किसी भी तरह से संरेखित करने के लिए स्वतंत्र है, जिसका अर्थ है कि दो अलग-अलग कंपाइलरों के साथ संकलित कोड एक-दूसरे से सही ढंग से लिंक नहीं हो सकता है और बिटफील्ड युक्त डेटा साझा नहीं कर सकता है। मास्किंग करना और खुद को स्थानांतरित करना इस समस्या को समाप्त करता है। – naasking

4

यदि आप पोर्टेबिलिटी चाहते हैं, तो बिटफील्ड से बचें। और यदि आप विशिष्ट कोड के प्रदर्शन में रुचि रखते हैं, तो अपने स्वयं के परीक्षण लिखने का कोई विकल्प नहीं है। याद रखें, बिटफील्ड हुड के नीचे प्रोसेसर के बिटवाई निर्देशों का उपयोग करेंगे।

+0

क्यों, बिटफील्ड ऑर्डरिंग के अलावा, बिटफील्ड गैर-पोर्टेबल होंगे? इसके अलावा कुछ प्रोसेसर बिटफील्ड डालने/निकालने का समर्थन करते हैं। 68020 ने उदाहरण के लिए किया था। –

+3

पैकिंग मुद्दे भी हैं। और सिर्फ इसलिए कि एक प्रोसेसर के पास एक विशेष उद्देश्य निर्देश है, इस बात की कोई गारंटी नहीं है कि संकलक इसका उपयोग करता है - यही कारण है कि मैंने कहा कि एक परीक्षण आवश्यक है। –

+2

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

1

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

+0

अधिक बिंदु पर, प्लेटफार्मों के क्रम में बिटफील्ड की गारंटी नहीं है। तो यदि आप हार्डवेयर रजिस्टर के लिए बिटफील्ड का उपयोग कर रहे हैं, तो आपको एक बहुत मुश्किल समय डिबगिंग करना होगा कि आपका हार्डवेयर ऐसा क्यों नहीं कर रहा है जो यह होना चाहिए। –

5

पहला व्यक्ति स्पष्ट है और दूसरी अभिव्यक्ति की गति त्रुटि-प्रवण है क्योंकि आपकी संरचना में कोई भी बदलाव दूसरी अभिव्यक्ति को गलत बना सकता है।

तो पहले का उपयोग करें।

+0

नहीं। पहला व्यक्ति असामान्य सुविधा का उपयोग करता है जो कि अधिकांश कोडर कभी स्पर्श नहीं करते हैं और समझ में नहीं आते हैं, जबकि दूसरा सादा idiomatic सी है। तो यह दूसरा विकल्प है जो दोनों अपने इरादे के बारे में स्पष्ट है, और लापरवाही से टूटा जाने की संभावना कम है देखरेख। – Porculus

+0

दूसरी अभिव्यक्ति के साथ गलत बात यह है कि '0x02' को परिभाषित स्थिर होना आवश्यक है ताकि डेवलपर जानता है कि इसका क्या अर्थ है। पहली बात यह है कि पहले गलत है कि संकलक दो बिट्स को 8-बिट बाइट में जहां भी चाहें डाल सकता है। लिनक्स कर्नेल बिट ऑर्डर और पैकिंग घोषित करने के लिए स्थिरांक के एक पूरे सेट को परिभाषित करता है, जिससे '# ifdef' ब्लॉक को बनाए रखने में कठिनाई होती है। और यह मान रहा है कि मंच 'char' को 8 बिट्स के रूप में परिभाषित करता है; मैंने उन प्लेटफ़ॉर्म के लिए विकसित किया है जो 'char' को 16 बिट्स के रूप में परिभाषित करते हैं क्योंकि डीएसपी बाइट्स को संबोधित नहीं कर सका, केवल शब्दों। –

12

बिटफिल्ड कोड को उचित रूप से उपयोग किए जाने पर कोड को अधिक स्पष्ट बनाते हैं। मैं केवल एक बिट सेविंग डिवाइस के रूप में बिटफील्ड का उपयोग करता हूं। एक सामान्य स्थान जिसे मैंने उन्हें देखा है, कंपाइलर्स में है: अक्सर प्रकार या प्रतीक जानकारी में सत्य/झूठे झंडे का समूह होता है। बिटकफील्ड यहां आदर्श हैं क्योंकि एक विशिष्ट कार्यक्रम में संकलित होने पर बनाए गए हजारों इन नोड्स होंगे।

मैं एक सामान्य एम्बेडेड प्रोग्रामिंग नौकरी करने के लिए बिटफील्ड का उपयोग नहीं करता: डिवाइस रजिस्टरों को पढ़ना और लिखना। मैं यहाँ शिफ्ट और मास्क का उपयोग करना पसंद करता हूं क्योंकि आपको वास्तव में बिट्स मिलते हैं जो दस्तावेज आपको बताता है और आपको बिटफील्ड के विभिन्न कंपाइलर कार्यान्वयन में अंतर के बारे में चिंता करने की ज़रूरत नहीं है।

गति के लिए, एक अच्छा कंपाइलर बिटकफील्ड के लिए एक ही कोड देगा जो मास्किंग करेगा।

+0

बिटफील्ड का उपयोग करने में समस्या यह है कि आपके पास कोई गारंटी नहीं है कि यह किसी भी स्थान को बचाएगा। कंपाइलर केवल प्रत्येक बिटफील्ड के लिए 32 बिट्स आवंटित कर सकता है, जैसे कि यह एक int था। ऐसा क्यों नहीं होगा? ज्यादातर मामलों में यह तेजी से होगा। – jalf

+0

दाएं। लेकिन यह अंतरिक्ष बचा सकता है। किसी भी स्मार्ट लोग बस ऐसा करने के लिए बिटफील्ड पर भरोसा करते हैं। –

+0

@jaif: मैं बीएस को बुलाता हूं। क्या आपके पास ऐसा कुछ भी है जो उस दावे का समर्थन करता है, मैं कल्पना को देखने के लिए बहुत आलसी हूं, लेकिन मुझे सच में संदेह है कि इसकी अनुमति है। – SoapBox

6

सी बिटकफील्ड उस समय से पैदा हुए थे जब उनका आविष्कार हुआ - अज्ञात कारण के लिए। लोगों ने उन्हें पसंद नहीं किया और इसके बजाय बिटवाई ऑपरेटरों का इस्तेमाल किया। आपको अन्य डेवलपर्स को सी बिटफील्ड कोड को समझने की उम्मीद नहीं करनी है।

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

1

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

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

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

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