सी

2016-08-09 9 views
5

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

बिट मास्क

#define MASK_8_V1(x) ((x) & 0xFF) 
#define MASK_8_V2(x) ((x) & 0x00FF) 

a = MASK_8_V1(b) 
a = MASK_8_V2(b) 

ये हमेशा जहां सभी बिट्स कम 8 ख से छोड़कर बाहर zero'd कर रहे हैं एक की चौड़ाई का मान प्राप्त करने के लिए गारंटी रहे हैं? क्या 2 संस्करणों के बीच कोई अंतर है क्योंकि यदि आवश्यक हो तो उन्हें विस्तारित किया जाना चाहिए?

झंडे

#define GEN_FLAG_16(x) ((0xFFFF) & ((unsigned) 1 << (x))) 
#define GEN_FLAG_32(x) ((0xFFFFFFFF) & ((unsigned long) 1 << (x))) 

मैं झंडा स्थिरांक पैदा करने के लिए एक सामान्य मैक्रो की जरूरत है, यह हमेशा सूचीबद्ध चौड़ाई के लिए एक ध्वज निरंतर में परिणाम होगा?

दोनों

#define CHECK_FLAG_16(x, y) ((x) & GEN_FLAG_16(y)) 
#define CHECK_FLAG_32(x, y) ((x) & GEN_FLAG_32(y)) 

if(CHECK_FLAG_16(a, b)) 
{ 
    // Do something. 
} 

पिछले परिदृश्यों का मेल, यह हमेशा भीतरी कोड यदि ख के मूल मूल्य में वांछित बिट सेट कर दिया जाता निष्पादित करेंगे?

सभी मामलों लिए, मान लें:

  • C90 या C99 अनुरूप संकलक
  • ए और बी देशी सी प्रकारों में से किसी मनमाना संयोजन, हमेशा पर हस्ताक्षर किए या अहस्ताक्षरित
  • एक्स एक सकारात्मक पूर्णांक का मूल्यांकन किया जा सकता हैके उपयोग का उल्लेख उन लोगों के लिए टाइप करें
  • मनमाने ढंग से देशी शब्द आकार

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

+1

आपने किस कंपाइलर को आजमाया? जब आपने कोशिश की तो क्या हुआ। और आपने इनके संबंध में चश्मा पढ़ा? और उन्होंने क्या कहा? –

+2

आप '0xff'' 0x00000000ff' से अलग क्यों हैं? और किसी भी कारण से आप निश्चित चौड़ाई प्रकार का उपयोग नहीं करते हैं जिन्हें विशेष रूप से निश्चित चौड़ाई डेटा के लिए परिभाषित किया जाता है? 'Stdint.h' देखें! साइड-नोट के रूप में: हस्ताक्षरित पूर्णांक का उपयोग न करें। – Olaf

+0

आपके पास दो बयान हैं जो कि एक-दूसरे से विरोधाभास करते हैं: 1. जब मैं कर सकता हूं तो पोर्टेबिलिटी पर जोर देने की कोशिश करता हूं। 2. मुझे केवल मूल्य के निचले 8 बिट्स में दिलचस्पी है। –

उत्तर

3

क्या ये हमेशा की चौड़ाई के मूल्य को प्राप्त करने की गारंटी देते हैं जहां सभी बिट्स शून्य से नीचे 8 को छोड़कर शून्य हो जाते हैं?

हां।

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

वहाँ 2 संस्करण

नहीं वे बराबर हैं के बीच कोई अंतर है।

वे यदि आवश्यक हो तो

यह आमतौर पर किसी भी भावना पर हस्ताक्षर किए प्रकार पर बिट के लिहाज से ऑपरेटरों का उपयोग करने के लिए नहीं है बढ़ाया हस्ताक्षर किया जाना चाहिए।

यदि मुझे ध्वज स्थिरांक उत्पन्न करने के लिए एक सामान्य मैक्रो की आवश्यकता है, तो क्या यह हमेशा सूचीबद्ध चौड़ाई के लिए ध्वज स्थिर होगा?

हां, लेकिन परिणाम int या long के आकार के आधार पर एक अलग प्रकार होगा।

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

यह मुख्य रूप से संकलक की समस्या है। साथ ही, यह स्पष्ट नहीं है कि uint8_t ऐसे सिस्टम पर एक समस्या होगी, हमेशा निहित पूर्णांक पदोन्नति होती है। लगता है जैसे आपके पास कुछ एल्गोरिदम समस्या थी, शायद uint8_t* पॉइंटर्स या उस तरह कुछ का उपयोग कर कोड।

#define MASK8_32(x) ((uint32_t)(x) & 0xFFul) 

#define GEN_FLAG_16(x) (uint16_t)(0xFFFFu & (1u << (x))) 
#define GEN_FLAG_32(x) (uint32_t)(0xFFFFFFFFu & (1ul << (x))) 

अब संभावित आकार के- पूर्णांक और निहित प्रकार पदोन्नति reliances के सबसे हटा दिया गया है:


pedantically, पूरी तरह से पोर्टेबल कोड कुछ ऐसा दिखाई देगा। यहाँ


मुख्य पोर्टेबिलिटी चिंताएं हैं:

  • आपका कोड, गैर पोर्टेबल है int और long इस तरह के कोड के आकार पर निर्भर करता है, क्योंकि उन प्रकार के किसी भी आकार के हो सकते हैं। Stdint.h से निश्चित-चौड़ाई पूर्णांक प्रकारों का उपयोग करना इन समस्याओं में से कई को हल करेगा।
  • आपका कोड डिफ़ॉल्ट प्रकारों और पूर्णांक अक्षरों के हस्ताक्षर से अनजान है। कई मामलों में आप हस्ताक्षरित ऑपरेटरों पर बिट-वार ऑपरेटरों का उपयोग करते हैं, जो हमेशा एक बुरा विचार है।
  • आप कैसे निहित प्रकार प्रोन्नति सी

यह पता चला है के रूप में में काम करते हैं, इन समस्याओं के सभी MISRA-C द्वारा हल किया जा सकता है की आम तौर पर अनजान लगते हैं। मैं मिसा-सी: 2012 खरीदने और शिक्षा उद्देश्यों के लिए इसे पढ़ने की सलाह दूंगा।


एक तरफ ध्यान दें के रूप में, a = OBSUCRE_MACRO(b); की तरह कोड अब तक कम पठनीयa = b & 0xFF; की तरह कोड से है। क्योंकि आप हमेशा यह मान सकते हैं कि पाठक एक सी प्रोग्रामर है, और जैसा कि सी भाषा जानता है, लेकिन आपकी निजी, गुप्त मैक्रो भाषा नहीं जानता है।

इसके अलावा, फ़ंक्शन-जैसे मैक्रोज़ असुरक्षित हैं और जब संभव हो तो इससे बचा जाना चाहिए।

तो मैं सवाल करता हूं कि ये मैक्रोज़ पहले स्थान पर क्या अच्छा करते हैं।

+0

धन्यवाद, यही वह है जिसे मैं ढूंढ रहा था। गैर-बाइट-एड्रेसेबल समस्या के बारे में, आप सही हैं, यह धारावाहिक संचार के लिए बाइट स्ट्रीमों को पार्स करने के लिए 'uint8_t *' का उपयोग करने से था। आप उस निर्भरता को कैसे हटा देंगे? अस्पष्ट मैक्रोज़ के लिए, मैं मानता हूं कि यह अनावश्यक हो सकता है। मैं कभी-कभी इन्हें निरंतरता लागू करने के लिए उपयोग करता हूं, लेकिन शायद यह एक खराब मामला है। एक मामला जहां यह अधिक समझ में आता है वह कुछ है '# परिभाषित करें CHECK_INCLUSIVE (वैल, मिनट, अधिकतम) (((वैल)> = (मिनट)) && ((वैल) <= (अधिकतम))) '। यह तुलना ऑपरेटर के साथ एक कठिन खोजने के लिए टाइपो की संभावना को हटा देता है। – ohitsderrick

+0

@ohitsderrick अनलिखित पहुंच के खिलाफ आप इतना कुछ नहीं कर सकते हैं जब तक कि संकलक ने इसके लिए कुछ स्मार्ट कार्य-लागू नहीं किया हो। यही है, जब आप सी कोड लिखते हैं जो "0x1001 पते पर 1 बाइट पढ़ता है" कहता है, तो कंपाइलर को कोड 0x1000 पर 1 शब्द पढ़ना, एक बाइट मास्क आउट करना होगा "। – Lundin

+0

@ohitsderrick उस मैक्रो के बारे में, ऐसा प्रतीत होता है कि सरल मैक्रो लिखने की तुलना में उस मैक्रो लिखते समय टाइपो या बग बनाना आसान है 'अगर (val> = min && val <= max) '... – Lundin

-1

आपको वास्तव में क्या करना चाहिए <stdint.h> में परिभाषित प्रकारों का उपयोग करें। आप जानते हैं कि आपको अपने झंडे के लिए कितनी बिट्स चाहिए, इसलिए आप उपयुक्त डेटाटाइप चुनें। उदाहरण के लिए:

#define GEN_FLAG_8(x) ((uint8_t)(1 << (x))) 
#define GEN_FLAG_16(x) ((uint16_t)(1 << (x))) 

तुम भी uint_fast16_t आदि के साथ एक ही गारंटी देता है लेकिन संभावित बड़ा डेटाटाइप्स के लिए चुनते सकता है

तो आप से बचने यह उल्लेख है कि आप के रूप में अच्छी मास्किंग करने के लिए मैक्रो या कार्यों बनाना चाहिए लायक है पूर्णांक अक्षर के साथ अपने कोड काली मिर्च।

+1

हां, मास्किंग मैक्रो पर अच्छा बिंदु। मैंने स्थिरता के लिए अपने मूल प्रश्न को संशोधित किया। एक साइड नोट के रूप में, आपके द्वारा सूचीबद्ध क्रम में कास्टिंग कुछ स्थितियों में गलत परिणाम उत्पन्न कर सकता है। उदाहरण के लिए, #Dfine GEN_FLAG_32 (x) ((uint32_t) (1 << (x))) 'जब लक्ष्य प्लेटफ़ॉर्म पर int 16 बिट्स है। यह हाल ही में मेरे साथ हुआ था। – ohitsderrick

+0

@ohitsderrick: साथ ही, यदि व्यवहार 'बिट' 32 बिट्स और' x == 31' है तो व्यवहार अपरिभाषित है। –