2009-02-06 19 views
5

पर deserialize मुझे नेटवर्क पर एक संचरण मिलता है जो वर्ण/बाइट्स की एक सरणी है। इसमें एक हेडर और कुछ डेटा शामिल है। मैं हेडर को एक स्ट्रक्चर पर मैप करना चाहता हूं। यहां एक उदाहरण दिया गया है:एक बाइट सरणी को एक संरचना

#pragma pack(1) 

struct Header 
{ 
    unsigned short bodyLength; 
    int msgID; 
    unsigned short someOtherValue; 
    unsigned short protocolVersion; 
}; 

int main() 
{ 
    boost::array<char, 128> msgBuffer; 
    Header header; 

    for(int x = 0; x < sizeof(Header); x++) 
     msgBuffer[x] = 0x01; // assign some values 

    memcpy(&header, msgBuffer.data(), sizeof(Header)); 

    system("PAUSE");  

    return 0; 
} 

क्या यह हमेशा काम करेगा कि संरचना में कभी भी कोई चर लंबाई लंबाई नहीं है? क्या ऐसा करने का कोई मंच स्वतंत्र/बेवकूफ तरीका है?

नोट:

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

उत्तर

5

कुछ प्रोसेसर की आवश्यकता होती है कि कुछ प्रकार ठीक तरह से गठबंधन हो जाएं। वे निर्दिष्ट पैकिंग स्वीकार नहीं करेंगे और एक हार्डवेयर जाल उत्पन्न करेंगे।

और यहां तक ​​कि सामान्य x86 पैक किए गए संरचनाओं पर भी कोड धीरे-धीरे चलने का कारण बन सकता है।

विभिन्न एंडियननेस प्लेटफ़ॉर्म के साथ काम करते समय आपको भी ध्यान रखना होगा।

वैसे, यदि आप कई प्रोग्रामिंग भाषाओं में बाइंडिंग के साथ एक सरल और मंच-स्वतंत्र संचार तंत्र चाहते हैं, तो YAMI पर एक नज़र डालें।

5

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

यही कारण है, लेकिन यह सब compilers पर लागू होता है।

मैं बाइट-बाय-बाइट फ़ील्ड पढ़ने और उन बाइट्स से बड़े क्षेत्र (इंट्स इत्यादि) को इकट्ठा करने की सलाह देता हूं। यह आपको अंतहीनता और पैडिंग का नियंत्रण देता है।

2

#pragma pack(1) निर्देश सबसे compilers पर काम करना चाहिए, लेकिन आप (आपके मामले में 10 अगर मेरी गणित सही है) काम कितना बड़ा अपने डेटा संरचना होना चाहिए और यह देखना होगा कि पैकिंग किया जा रहा है printf("%d", sizeof(Header)); का उपयोग करके देख सकते हैं।

जैसा कि अन्य ने कहा है कि यदि आप आर्किटेक्चर के बीच जा रहे हैं तो आपको अभी भी एंडियननेस से सावधान रहना होगा।

0

मुझे पता है कि मैं किसके साथ संवाद कर रहा हूं, इसलिए मुझे वास्तव में अंतहीनता के बारे में चिंता करने की ज़रूरत नहीं है। लेकिन मैं संकलक विशिष्ट आदेशों से वैसे भी दूर रहना पसंद करता हूं।

तो कैसे इस बारे में:

const int kHeaderSizeInBytes = 6; 

struct Header 
{ 
    unsigned short bodyLength; 
    unsigned short msgID; 
    unsigned short protocolVersion; 

    unsigned short convertUnsignedShort(char inputArray[sizeof(unsigned short)]) 
     {return (((unsigned char) (inputArray[0])) << 8) + (unsigned char)(inputArray[1]);} 

    void operator<<(char inputArray[kHeaderSizeInBytes]) 
    { 
     bodyLength = convertUnsignedShort(inputArray); 
     msgID = convertUnsignedShort(inputArray + sizeof(bodyLength)); 
     protocolVersion = convertUnsignedShort(inputArray + sizeof(bodyLength) + sizeof(msgID)); 
    } 
}; 

int main() 
{ 
    boost::array<char, 128> msgBuffer; 
    Header header; 

    for(int x = 0; x < kHeaderSizeInBytes; x++) 
     msgBuffer[x] = x; 

    header << msgBuffer.data(); 

    system("PAUSE");  

    return 0; 
} 

pragma से छुटकारा हो जाता है, लेकिन यह सामान्य रूप में उद्देश्य के रूप में मैं चाहता हूँ नहीं है। हर बार जब आप हेडर में फ़ील्ड जोड़ते हैं तो आपको < < फ़ंक्शन को संशोधित करना होगा। क्या आप किसी भी तरह से संरचना क्षेत्रों पर फिर से चल सकते हैं, फ़ील्ड का प्रकार प्राप्त कर सकते हैं और संबंधित फ़ंक्शन को कॉल कर सकते हैं?

+0

संरचना क्षेत्रों पर पुनरावृत्ति के बारे में: क्या आपको संरचना का उपयोग करना है? मैं पूछ रहा हूं क्योंकि इसे एक ट्यूपल द्वारा प्रतिस्थापित करने से खेतों के पुनरावृत्ति की अनुमति मिल जाएगी। –

1

मैं बाइट द्वारा बाइट पढ़ने के विचार से असहमत हूं। यदि आप संरचना घोषणा में संरचना पैकिंग का ख्याल रखते हैं, तो आप बिना किसी समस्या के संरचना में प्रतिलिपि बना सकते हैं। एंडियननेस समस्या के लिए बाइट द्वारा बाइट पढ़ना फिर से समस्या हल करता है लेकिन आपको एक सामान्य समाधान नहीं देता है। वह विधि बहुत लंगड़ा है। मैंने इसी तरह की नौकरी के लिए ऐसा कुछ किया है और यह बिना किसी गड़बड़ी के ठीक काम करता है।

इस बारे में सोचें। मेरे पास एक संरचना है, मेरे पास उस संरचना की एक समान परिभाषा भी है। आप इसे हाथ से बना सकते हैं लेकिन मैंने इसके लिए एक पार्सर लिखा है और इसे अन्य चीजों के लिए भी इस्तेमाल किया है।

उदाहरण के लिए, ऊपर दी गई संरचना की परिभाषा "एस आई एस" है। (एस = शॉर्ट, i = int) फिर मैं स्ट्रक्चर एड्रेस, इस परिभाषा और संरचना पैकिंग विकल्प को इस स्ट्रक्चर के एक विशेष समारोह में देता हूं जो एंडियननेस चीज़ और वॉयला से संबंधित है।

स्विचइंडियन टोबीग (& हेडर, "एस आई एस एस", 4); // 4 = संरचना पैकिंग विकल्प

1

मुझे बताओ अगर मैं इसे इस तरह से कर रही है गलत हूँ, लेकिन AFAIK, आप की गारंटी देगा कि डेटा सही है - संभालने प्रकार अपने विभिन्न प्लेटफार्मों पर एक ही आकार के होते हैं:

#include <array> 
#include <algorithm> 

//#pragma pack(1) // not needed 

struct Header 
{ 
    unsigned short bodyLength; 
    int msgID; 
    unsigned short someOtherValue; 
    unsigned short protocolVersion; 
    float testFloat; 

    Header() : bodyLength(42), msgID(34), someOtherValue(66), protocolVersion(69), testFloat(3.14f) {} 
}; 

int main() 
{ 
    std::tr1::array<char, 128> msgBuffer; 
    Header header; 

    const char* rawData = reinterpret_cast< const char* >(&header); 

    std::copy(rawData, rawData + sizeof(Header), msgBuffer.data()); // assuming msgBuffer is always big enough 

    system("PAUSE");  

    return 0; 
} 

यदि आपके लक्षित प्लेटफॉर्म पर प्रकार अलग हैं, तो आपको प्रत्येक प्रकार के उपयोग के लिए उपनाम (टाइपपीफ) का उपयोग करना होगा ताकि प्रत्येक प्रयुक्त प्रकार का आकार समान हो।

+0

उहम, आप दूसरी तरफ जा रहे हैं (एक बाइट सरणी में एक संरचना को परिवर्तित करना)। और यहां तक ​​कि यह काफी काम नहीं करता क्योंकि यह चाहिए क्योंकि आप संरचना के पैडिंग को सरणी में कॉपी कर रहे हैं। – drby

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