2009-07-19 15 views
7

का बाइनरी संस्करण Iostreams का एक बाइनरी संस्करण लिख रहा है। यह अनिवार्य रूप से आपको बाइनरी फाइलें लिखने की अनुमति देता है, लेकिन आपको फ़ाइल के प्रारूप पर अधिक नियंत्रण देता है। उदाहरण उपयोग: (। जहां उपसर्ग u16le है)iostream

my_file << binary::u32le << my_int << binary::u16le << my_string; 

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

हुस्ट के तहत, iostreams, स्ट्रीमबफ का उपयोग करते हैं। यह वास्तव में एक शानदार डिजाइन है - iostreams कोड में 'int' का क्रमबद्धीकरण कोड करता है, और अंतर्निहित स्ट्रीमबफ बाकी को संभालता है। इस प्रकार, आपको कोउट, एफस्ट्रीम, स्ट्रिंगस्ट्रीम इत्यादि मिलते हैं। इनमें से सभी, आईस्ट्रीम और स्ट्रीमबफ दोनों, आम तौर पर चार पर होते हैं, लेकिन कभी-कभी वेचर के रूप में भी। मेरा डेटा, हालांकि, एक बाइट स्ट्रीम है, जो सबसे अच्छा 'unsigned char' द्वारा दर्शाया गया है।

मेरा पहला प्रयास unsigned char पर आधारित कक्षाओं को टेम्पलेट करना था। std::basic_string टेम्पलेट्स काफी अच्छी हैं, लेकिन streambuf नहीं है। मैं codecvt नामक कक्षा के साथ कई समस्याओं में भाग गया, जिसे मैं कभी भी unsigned char विषय का पालन नहीं कर सका। यह दो प्रश्न उठाता है:

1) ऐसी चीजों के लिए एक स्ट्रीमबफ जिम्मेदार क्यों है? ऐसा लगता है जैसे कोड-रूपांतरण एक स्ट्रीमबफ की ज़िम्मेदारी से बाहर निकलते हैं - स्ट्रीमबफ को एक स्ट्रीम लेनी चाहिए, और उस से डेटा को बफर करना चाहिए। और कुछ नहीं। कोड रूपांतरणों के रूप में उच्च स्तर के रूप में कुछ ऐसा लगता है जैसे यह iostreams में होना चाहिए।

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

size_t read(unsigned char *buffer, size_t size) 
{ 
    size_t ret; 
    ret = stream()->sgetn(reinterpret_cast<char *>(buffer), size); 
    // deal with ret for return size, eof, errors, etc. 
    ... 
} 

अच्छा समाधान, खराब समाधान?


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

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

bostream &operator << (uint8_t n); 
bostream &operator << (uint16_t n); 
bostream &operator << (uint32_t n); 
bostream &operator << (uint64_t n); 
समय में

हालांकि,: यह एक वैकल्पिक हल का एक सा है, मैं orginally thusly < < ऑपरेटर ओवरलोडिंग की कोशिश की थी। अस्पष्ट कार्य कॉल के साथ मुझे कई समस्याएं थीं। यह विशेष रूप से स्थिरांक के बारे में सच था, हालांकि आप एक पोस्टर के रूप में सुझाव दे सकते थे, कास्ट कर सकते थे या इसे const <type> के रूप में घोषित कर सकते थे। मुझे याद है कि हालांकि कुछ और बड़ी समस्या थी।

+0

आपकी संदिग्ध फ़ंक्शन कॉल समस्या इस तथ्य के कारण हो सकती है कि [u] int32_t को आमतौर पर "[हस्ताक्षरित] लंबा" के रूप में परिभाषित किया जाता है। तो यदि आप एक "[हस्ताक्षरित] int" लिखने का प्रयास करते हैं, जो संख्यात्मक अक्षर होते हैं, तो पदोन्नति आवश्यक है, लेकिन प्रचार करने के लिए प्रकार संदिग्ध है (उदाहरण के लिए लंबे बनाम डबल)। –

+0

क्या आप कृपया उन संघर्षों पर कंपाइलर आउटपुट पोस्ट कर सकते हैं जिनके साथ आपने हस्ताक्षर किए गए चार स्ट्रीमबफ के साथ किया था? – Basilevs

उत्तर

1

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

आप स्वचालित रूप से प्रकार अलग करने के लिए भार के उपयोग करते हैं, आप केवल जब यह चर के घोषित प्रकार से अलग था प्रकार निर्दिष्ट करने की आवश्यकता होगी:

Stream& operator<<(int8_t); 
Stream& operator<<(uint8_t); 
Stream& operator<<(int16_t); 
Stream& operator<<(uint16_t); 
etc. 

uint32_t x; 
stream << x << (uint16_t)x; 

घोषित प्रकार के अलावा अन्य किया जाएगा प्रकार पढ़ना थोड़ा गड़बड़ आम तौर पर, हालांकि, आउटपुट प्रकार से अलग प्रकार के चर से पढ़ने या लिखने से बचा जाना चाहिए, मुझे लगता है।

मेरा मानना ​​है कि std :: codecvt का डिफ़ॉल्ट संस्करण कुछ भी नहीं करता है, सब कुछ के लिए "noconv" लौटाता है। "विस्तृत" वर्ण धाराओं का उपयोग करते समय यह वास्तव में कुछ भी करता है। क्या आप codecvt के लिए एक समान परिभाषा स्थापित नहीं कर सकते? यदि, किसी कारण से, आपकी स्ट्रीम के लिए नो-ऑप कोडेकवेट परिभाषित करना अव्यवहारिक है, तो मुझे आपके कास्टिंग समाधान के साथ कोई समस्या नहीं दिखाई दे रही है, खासकर जब से यह एक स्थान से अलग है।

अंत में, क्या आप वाकई कुछ मानक धारावाहिक कोड, जैसे Boost का उपयोग करके बेहतर नहीं होंगे, बल्कि अपना खुद का रोलिंग करने के बजाय?

+1

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

+0

अच्छा, ऐसा लगता है जैसे आप जानते हैं कि आप क्या कर रहे हैं। मेरे पास यह सब प्रतिक्रिया है। यदि आप ओवरलोडिंग या कोडेकवेट समस्याओं पर एक और दरार लेना चाहते हैं, तो मुझे यकीन है कि इसे देखने में खुशी होगी। –

+0

मुझे लगता है कि यह जाने का रास्ता है। शायद आपको 'संदिग्ध फ़ंक्शन कॉल' त्रुटियों को काम करने का प्रयास करना चाहिए। मुझे नहीं लगता (मैंने कोशिश नहीं की है) कि ओवरलोड डिज़ाइन त्रुटिपूर्ण है (मुझे गलत साबित किया जा सकता है) –

0

हमें कुछ करने की ज़रूरत है जो आप कर रहे हैं लेकिन हम एक और मार्ग का पालन करते हैं। मुझे आपकी रुचि है कि आपने अपना इंटरफ़ेस कैसे परिभाषित किया है। मुझे पता नहीं है कि आप कैसे प्रबंधित कर सकते हैं मैनिपुलेटर्स आपने परिभाषित किया है (बाइनरी :: u32le, binaryu16le)।

बुनियादी_स्ट्रीम के साथ, मैनिपुलेटर नियंत्रित करता है कि निम्नलिखित सभी तत्व कैसे पढ़े जाएंगे/लिखे जाएंगे, लेकिन आपके मामले में, शायद यह समझ में नहीं आता है, क्योंकि आकार (आपके मैनिपुलेटर जानकारी का हिस्सा) पारित चर द्वारा प्रभावित होता है और बाहर।

binary_istream in; 
int i; 
int i2; 
short s; 
in >> binary::u16le >> i >> binary::u32le >> i2 >> s; 

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

आकार मैनिपुलेटर्स के लिए (मेरी राय में) प्रतीत नहीं होता है।

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

+0

मैंने आपके उत्तर के संबंध में प्रश्न में कुछ संपादन किए हैं। आप और अन्य पोस्टर ने अब मुझे मैनिपुलेटर्स का उपयोग करने के बारे में फिर से सोच लिया है (अच्छा नाम, उन्हें एक की जरूरत है ...)। मुझे लगता है कि संदिग्ध फ़ंक्शन कॉल के साथ समस्याएं थीं। यह esp है। << 6 में सच है, हालांकि यह << uint16_t (6) में किया जा सकता है। मैनिपुलेटर्स बने रहते हैं, और यह 32 बिट मैनिपुलेटर के साथ 16 बिट वैरिएबल में पढ़ने का प्रयास करने में त्रुटि है। मैं इस उपयोग के बारे में सोचने जा रहा हूं, हालांकि, और देख सकता हूं कि शायद आपके द्वारा वर्णित पैटर्न एक बेहतर फिट है या नहीं। – Thanatos

+0

नाम मेरा नहीं है, बल्कि मानक है। सी ++ मानक में, अध्याय 27.6 का शीर्षक है: 'स्वरूपण और मैनिपुलेटर्स', और आपके संस्करण के विपरीत, उन्हें धाराओं में पारित वस्तुओं के रूप में लागू नहीं किया जाता है बल्कि स्ट्रीम के अंदर निष्पादित किए जाने वाले मुक्त कार्यों (templated) के रूप में लागू नहीं किया जाता है (ios_base या basic_ios <>)। प्रत्येक मामले में वे दिए गए प्रकार (basic_stream <>, basic_ios <> या ios_base) –

0

मैं ऑपरेटर < < का उपयोग नहीं करता क्योंकि यह फ़ॉर्मेटेड टेक्स्ट I/O से बहुत गहराई से जुड़ा हुआ है।

मैं वास्तव में इसके लिए एक ऑपरेटर ओवरलोड का उपयोग नहीं करता। मुझे एक और मुहावरे मिलेगा।

+1

पर संदर्भ लेते हैं और वापस लौटते हैं, मैं केवल एक स्ट्रीम से/चीजों के आंदोलन में इसका उपयोग मानता हूं, लेकिन शायद मैं आपका बिंदु देख सकता हूं। फिर भी, यह सिर्फ एक फ़ंक्शन कॉल है - इसे आसानी से .read (...) या .write (...) के साथ प्रतिस्थापित किया जा सकता है, लेकिन फिर आप समाप्त हो जाएंगे: stream.read (x) .read (y) .read (z) जो समझ में आता है या नहीं। हालांकि, चूंकि वर्ग पदानुक्रम Iostreams से मेल खाता है, इसलिए एपीआई क्यों नहीं? – Thanatos

+0

मानक पुस्तकालय में पहले से ही विधियां हैं जो बाइनरी डेटा को पढ़ और लिख सकती हैं। वे विधियां हैं, << or >> के अधिभार नहीं हैं।बाइनरी I/O के लिए << and >> का उपयोग न करने का कारण यह है कि लोग स्वरूपित इनपुट और आउटपुट को देखते हैं जब वे उन ऑपरेटरों को देखते हैं। स्वरूपण का अर्थ स्थानीय, फील्ड औचित्य इत्यादि जैसी चीजों का तात्पर्य है। आप बाइनरी I/O के साथ ऐसा नहीं कर रहे हैं, यही कारण है कि मानक लाइब्रेरी बुनियादी_स्ट्रीम :: पढ़ और मूल_स्ट्रीम :: लिखने के तरीके प्रदान करती है। – legalize

+0

आप _ary_ बाइनरी I/O के साथ सबसे अधिक कर रहे हैं। लोकेल में एंडियननेस या फ्लोटिंग पॉइंट प्रारूप होते हैं, फ़ील्ड औचित्य को संरेखण द्वारा प्रतिस्थापित किया जाता है। बाइनरी स्वरूपित आउटपुट पाठ के समान है। – Basilevs

2

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

मेरे समाधान इस पद्धति पर आधारित था (जो केवल एक ही मशीन पर अस्थायी रूप से डेटा को क्रमानुसार करने की जरूरत है, और इसलिए endianness को संबोधित करने की आवश्यकता नहीं है):

// deducible template argument read 
template <class T> 
void read_raw(std::istream& stream, T& value, 
    typename boost::enable_if< boost::is_pod<T> >::type* dummy = 0) 
{ 
    stream.read(reinterpret_cast<char*>(&value), sizeof(value)); 
} 

// explicit template argument read 
template <class T> 
T read_raw(std::istream& stream) 
{ 
    T value; 
    read_raw(stream, value); 
    return value; 
} 

template <class T> 
void write_raw(std::ostream& stream, const T& value, 
    typename boost::enable_if< boost::is_pod<T> >::type* dummy = 0) 
{ 
    stream.write(reinterpret_cast<const char*>(&value), sizeof(value)); 
} 

मैं तो आगे किसी के लिए read_raw/write_raw अतिभारित गैर-पीओडी प्रकार (जैसे तार)। ध्यान दें कि read_raw का केवल पहला संस्करण अधिभारित होना चाहिए; यदि आप use ADL correctly, दूसरा (1-arg) संस्करण बाद में और अन्य नामस्थानों में परिभाषित 2-Arg ओवरलोड को कॉल कर सकता है।

लिखें उदाहरण:

int32_t x; 
int64_t y; 
int8_t z; 
write_raw(is, x); 
write_raw(is, y); 
write_raw<int16_t>(is, z); // explicitly write int8_t as int16_t 

पढ़ें उदाहरण:

int32_t x = read_raw<int32_t>(is); // explicit form 
int64_t y; 
read_raw(is, y); // implicit form 
int8_t z = numeric_cast<int8_t>(read_raw<int16_t>(is)); 

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

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