सीधे फ़ाइल से संरचना में न पढ़ें! पैकिंग अलग हो सकती है, आपको प्रगा पैक या इसी तरह के कंपाइलर विशिष्ट संरचनाओं के साथ झुकाव करना होगा। बहुत अविश्वसनीय बहुत सारे प्रोग्रामर इससे दूर हो जाते हैं क्योंकि उनके कोड को आर्किटेक्चर और सिस्टम की विस्तृत संख्या में संकलित नहीं किया जाता है, लेकिन इसका मतलब यह नहीं है कि यह करना ठीक है!
एक अच्छा वैकल्पिक तरीका हेडर को पढ़ने के लिए है, जो भी, एक बफर में और तीन से पार्स में है, परमाणु संचालन में I/O ओवरहेड से बचने के लिए एक हस्ताक्षरित 32 बिट पूर्णांक पढ़ने के लिए!
char buffer[32];
char* temp = buffer;
f.read(buffer, 32);
RECORD rec;
rec.foo = parse_uint32(temp); temp += 4;
rec.bar = parse_uint32(temp); temp += 4;
memcpy(&rec.fooword, temp, 11); temp += 11;
memcpy(%red.barword, temp, 11); temp += 11;
rec.baz = parse_uint16(temp); temp += 2;
parse_uint32 की घोषणा इस प्रकार दिखाई देगा:
uint32 parse_uint32(char* buffer)
{
uint32 x;
// ...
return x;
}
यह एक बहुत ही सरल अमूर्त है, यह सूचक भी अपडेट करने के व्यवहार में कोई अतिरिक्त खर्च नहीं करता है:
uint32 parse_uint32(char*& buffer)
{
uint32 x;
// ...
buffer += 4;
return x;
}
बाद का फॉर्म बफर को पार्स करने के लिए क्लीनर कोड की अनुमति देता है; जब आप इनपुट से विश्लेषण करते हैं तो पॉइंटर स्वचालित रूप से अपडेट हो जाता है।
इसी तरह, memcpy एक सहायक हो सकता है, कुछ की तरह:
void parse_copy(void* dest, char*& buffer, size_t size)
{
memcpy(dest, buffer, size);
buffer += size;
}
व्यवस्था के इस प्रकार की सुंदरता आप नाम स्थान "little_endian" और "big_endian", तो आप इस में क्या कर सकते हैं हो सकता है वह यह है कि अपने कोड:
using little_endian;
// do your parsing for little_endian input stream here..
आसान एक ही कोड के लिए endianess स्विच करने के लिए, हालांकि, शायद ही कभी जरूरत सुविधा .. फ़ाइल स्वरूपों आमतौर पर वैसे भी एक निश्चित endianess है।
वर्चुअल विधियों के साथ कक्षा में इसे अमूर्त न करें; सिर्फ भूमि के ऊपर जोड़ने के लिए, लेकिन करने के लिए स्वतंत्र यदि ऐसा है तो इच्छुक लगेगा:
little_endian_reader reader(data, size);
uint32 x = reader.read_uint32();
uint32 y = reader.read_uint32();
पाठक वस्तु स्पष्ट रूप से सिर्फ सूचक चारों ओर एक पतली आवरण होगा। आकार पैरामीटर त्रुटि जांच के लिए होगा, यदि कोई हो। इंटरफ़ेस प्रति-सी के लिए वास्तव में अनिवार्य नहीं है।
ध्यान दें कि अंतहीनता का चयन COMPILATION TIME पर किया गया था (चूंकि हम little_endian_reader ऑब्जेक्ट बनाते हैं), इसलिए हम वर्चुअल विधि ओवरहेड को विशेष रूप से अच्छे कारण के लिए नहीं बुलाते हैं, इसलिए मैं इस दृष्टिकोण के साथ नहीं जाऊंगा। ;-)
इस स्तर पर "फ़ाइलफॉर्मेट स्ट्रक्चर" को आस-पास रखने का कोई वास्तविक कारण नहीं है, आप डेटा को अपनी पसंद के अनुसार व्यवस्थित कर सकते हैं और इसे किसी भी विशिष्ट संरचना में जरूरी नहीं पढ़ सकते हैं; आखिरकार, यह सिर्फ डेटा है। जब आप छवियों जैसी फ़ाइलों को पढ़ते हैं, तो आपको वास्तव में शीर्षलेख की आवश्यकता नहीं होती है .. आपके पास अपने छवि कंटेनर होना चाहिए जो सभी फ़ाइल प्रकारों के लिए समान है, इसलिए एक विशिष्ट प्रारूप को पढ़ने के लिए कोड को फ़ाइल को पढ़ना, समझना और सुधारना चाहिए डेटा & पेलोड स्टोर करें। =)
मेरा मतलब है, क्या यह जटिल दिखता है?
uint32 xsize = buffer.read<uint32>();
uint32 ysize = buffer.read<uint32>();
float aspect = buffer.read<float>();
कोड यह अच्छा लग सकता है, और वास्तव में कम ओवरहेड हो सकता है! यदि endianess फ़ाइल और वास्तुकला कोड के लिए संकलित किया गया है के लिए एक ही है, innerloop इस तरह दिख सकता:
uint32 value = *reinterpret_cast<uint32*>)(ptr); ptr += 4;
return value;
कि कुछ आर्किटेक्चर पर अवैध हो सकता है, ताकि अनुकूलन एक बुरा विचार हो सकता है, और धीमी उपयोग करते हैं, लेकिन और अधिक मजबूत दृष्टिकोण:
uint32 value = ptr[0] | (static_cast<uint32>(ptr[1]) << 8) | ...; ptr += 4;
return value;
एक x86 कि bswap या mov में संकलित कर सकते हैं, जो काफी कम भूमि के ऊपर है, तो विधि inlined है पर; कंपाइलर इंटरमीडिएट कोड में "चाल" नोड डालेगा, और कुछ भी नहीं, जो काफी कुशल है। अगर संरेखण एक समस्या है तो पूर्ण पठन-शिफ्ट-या अनुक्रम उत्पन्न हो सकता है, बाहर निकल सकता है, लेकिन अभी भी बहुत कमजोर नहीं है। यदि एलएसबी के पते का परीक्षण करें और देखें कि पार्सिंग के तेज या धीमी संस्करण का उपयोग कर सकते हैं तो तुलना-शाखा ऑप्टिमाइज़ेशन की अनुमति दे सकती है। लेकिन इसका मतलब हर पठन में परीक्षण के लिए जुर्माना होगा। प्रयास के लायक नहीं हो सकता है।
ओह, ठीक है, हम हेडर और सामान पढ़ रहे हैं, मुझे नहीं लगता कि यह बहुत से अनुप्रयोगों में एक बाधा है। अगर कुछ कोडेक कुछ सचमुच तंग आंतरिकता कर रहा है, तो फिर से, एक अस्थायी बफर में पढ़ना और वहां से डिकोडिंग अच्छी तरह से सलाह दी जाती है। वही सिद्धांत .. डेटा की एक बड़ी मात्रा को संसाधित करते समय कोई भी फाइल से बाइट-एट-टाइम नहीं पढ़ता है। खैर, असल में, मैंने उस तरह का कोड बहुत बार देखा और "आप ऐसा क्यों करते हैं" के सामान्य जवाब यह है कि फ़ाइल सिस्टम ब्लॉक पढ़ता है और बाइट्स स्मृति से आते हैं, सच है, लेकिन वे एक गहरी कॉल स्टैक से गुज़रते हैं जो कुछ बाइट प्राप्त करने के लिए उच्च ओवरहेड है!
फिर भी, एक बार पार्सर कोड लिखें और ज़िलियन बार -> महाकाव्य जीत का उपयोग करें।
सीधे फ़ाइल से संरचना में पढ़ना: इसे फोल्ड न करें!
आपने उनके बारे में नहीं पूछा, लेकिन इस तरह के विरासत कोड के साथ काम करते समय विचार करने के लिए एक और बात बिटफील्ड है। ऑर्डर जो बिटफिल्ड पैक किए गए हैं, वे संकलक और प्लेटफार्म दोनों निर्भर और प्रोसेसर की अंतहीनता से असंबंधित हो सकते हैं। – Dan