c++ सी/सी++: फोर्स बिट फील्ड ऑर्डर और संरेखण




bit-manipulation endianness (5)

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

struct Message
{
  unsigned int version : 3;
  unsigned int type : 1;
  unsigned int id : 5;
  unsigned int data : 6;
} __attribute__ ((__packed__));

जीसीसी कंपाइलर के साथ एक इंटेल प्रोसेसर पर, फ़ील्ड को दिखाए गए अनुसार मेमोरी में रखा गया था। संदेश.वर्जन बफर में पहला 3 बिट था, और Message.type का पालन किया। अगर मुझे विभिन्न कंपाइलर्स के लिए समकक्ष स्ट्रक्चर पैकिंग विकल्प मिलते हैं, तो क्या यह क्रॉस-प्लेटफार्म होगा?


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


बिट फ़ील्ड कंपाइलर से कंपाइलर से व्यापक रूप से भिन्न होते हैं, क्षमा करें।

जीसीसी के साथ, बड़ी एंडियन मशीनें बिट्स को पहले अंत में बिछाती हैं और छोटी एंडियन मशीनें बिट्स को पहले थोड़ा कम करती हैं।

के एंड आर का कहना है, "संरचनाओं के निकट [बिट-] क्षेत्र के सदस्यों को कार्यान्वयन-निर्भर भंडारण इकाइयों में कार्यान्वयन-निर्भर दिशा में पैक किया जाता है। जब किसी अन्य क्षेत्र के बाद कोई फ़ील्ड फिट नहीं होगा ... इसे इकाइयों या इकाई के बीच विभाजित किया जा सकता है गद्देदार 0 का एक अज्ञात क्षेत्र इस पैडिंग को बल देता है ... "

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

यह अंतिम कथन पैडिंग के कारण गैर-बिटफील्ड पर भी लागू होता है - हालांकि सभी कंपाइलरों को संरचना के बाइट पैकिंग को मजबूर करने का कोई तरीका प्रतीत होता है, क्योंकि मुझे लगता है कि आप पहले ही जीसीसी के लिए खोज चुके हैं।


बिटफिल्ड से बचा जाना चाहिए - वे एक ही मंच के लिए भी कंपाइलर्स के बीच बहुत पोर्टेबल नहीं हैं। सी 99 मानक से 6.7.2.1/10 - "संरचना और संघ विनिर्देशक" (सी 0 9 मानक में समान शब्द है):

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

आप गारंटी नहीं दे सकते कि कोई छोटा क्षेत्र एक अंतर सीमा को 'फैलाएगा' या नहीं और आप यह निर्दिष्ट नहीं कर सकते कि क्या बिटफील्ड int के निम्न-अंत या int के उच्च अंत में शुरू होता है (यह प्रोसेसर है या नहीं बड़े एंडियन या छोटे-एंडियन)।

बिटमैस्क पसंद करें। बिट्स सेट, साफ़ और परीक्षण करने के लिए इनलाइन (या यहां तक ​​कि मैक्रोज़) का उपयोग करें।


endianness बाइट आदेश के बारे में बात कर रहे हैं थोड़ा आदेश नहीं। आजकल , यह 99% सुनिश्चित है कि बिट ऑर्डर तय किए गए हैं। हालांकि, बिटफील्ड का उपयोग करते समय, अंतराल को गिनती में लिया जाना चाहिए। नीचे उदाहरण देखें।

#include <stdio.h>

typedef struct tagT{

    int a:4;
    int b:4;
    int c:8;
    int d:16;
}T;


int main()
{
    char data[]={0x12,0x34,0x56,0x78};
    T *t = (T*)data;
    printf("a =0x%x\n" ,t->a);
    printf("b =0x%x\n" ,t->b);
    printf("c =0x%x\n" ,t->c);
    printf("d =0x%x\n" ,t->d);

    return 0;
}

//- big endian :  mips24k-linux-gcc (GCC) 4.2.3 - big endian
a =0x1
b =0x2
c =0x34
d =0x5678
// - little endian : gcc (Ubuntu 4.3.2-1ubuntu11) 4.3.2
a =0x2
b =0x1
c =0x34
d =0x7856

अधिकांश समय, शायद, लेकिन उस पर खेत पर शर्त न लगाएं, क्योंकि यदि आप गलत हैं, तो आप बड़ी हार जाएंगे।

यदि आपको वास्तव में, वास्तव में समान बाइनरी जानकारी की आवश्यकता है, तो आपको बिटमैस्क के साथ बिटफील्ड बनाने की आवश्यकता होगी - उदाहरण के लिए आप संदेश के लिए एक हस्ताक्षरित शॉर्ट (16 बिट) का उपयोग करते हैं, और उसके बाद तीन शीर्षतम बिट्स का प्रतिनिधित्व करने के लिए वर्जनमास्क = 0xE000 जैसी चीजें बनाते हैं।

Structs के भीतर संरेखण के साथ एक ही समस्या है। उदाहरण के लिए, स्पार्क, पावरपीसी, और 680x0 सीपीयू सभी बड़े-एंडियन हैं, और स्पार्क और पावरपीसी कंपाइलर्स के लिए सामान्य डिफ़ॉल्ट 4-बाइट सीमाओं पर संरचना सदस्यों को संरेखित करना है। हालांकि, 680x0 के लिए उपयोग किए जाने वाले एक कंपाइलर को केवल 2-बाइट सीमाओं पर गठबंधन किया गया था - और संरेखण को बदलने का कोई विकल्प नहीं था!

तो कुछ structs के लिए, स्पार्क और पावरपीसी के आकार समान हैं, लेकिन 680x0 पर छोटे हैं, और कुछ सदस्य संरचना के भीतर विभिन्न मेमोरी ऑफ़सेट में हैं।

यह एक परियोजना के साथ एक समस्या थी जिस पर मैंने काम किया था, क्योंकि स्पार्क पर चल रही एक सर्वर प्रक्रिया क्लाइंट से पूछताछ करेगी और पता लगाएगी कि यह बड़ा-एंडियन था, और मान लीजिए कि यह नेटवर्क पर बाइनरी स्ट्रक्चर को बाहर कर सकता है और ग्राहक सामना कर सकता है। और यह पावरपीसी ग्राहकों पर ठीक काम करता है, और 680x0 ग्राहकों पर बड़े पैमाने पर दुर्घटनाग्रस्त हो गया। मैंने कोड नहीं लिखा, और समस्या को खोजने में काफी समय लगा। लेकिन मैंने ऐसा करने के बाद इसे ठीक करना आसान था।







bit