2012-04-14 37 views
7

बुनियादी सवाल लिखा के बारे में उलझन में लिखें, लेकिन मैं इस struct की उम्मीद (चार के लिए 1, 3 अहस्ताक्षरित ints के लिए 12) अंतरिक्ष के 13 बाइट्स पर कब्जा करने के लिए। इसके बजाय, sizeof(ESPR_REL_HEADER) मुझे 16 बाइट देता है।सी में एक फ़ाइल के लिए कच्चे struct सामग्री (बाइट) वास्तविक आकार

typedef struct { 
    unsigned char version; 
    unsigned int root_node_num; 
    unsigned int node_size; 
    unsigned int node_count; 
} ESPR_REL_HEADER; 

मुझे क्या करना कोशिश कर रहा हूँ कुछ मान के साथ इस struct प्रारंभ और एक फ़ाइल के शुरू करने के उसमें शामिल डेटा (कच्चे बाइट्स) लिखते हैं, ताकि जब मैं मैं बाद में इस फ़ाइल को खोलने मैं कर सकते हैं इस संरचना का पुनर्निर्माण करें और बाकी फ़ाइल में क्या है इसके बारे में कुछ मेटा डेटा प्राप्त करें।

मैं struct आरंभ कर रहा हूँ और इस तरह फाइल करने के लिए इसे लिखने:

int esprime_write_btree_header(FILE * fp, unsigned int node_size) { 
    ESPR_REL_HEADER header = { 
    .version  = 1, 
    .root_node_num = 0, 
    .node_size  = node_size, 
    .node_count = 1 
    }; 

    return fwrite(&header, sizeof(ESPR_REL_HEADER), 1, fp); 
} 

node_size कहाँ वर्तमान में 4, जबकि मैं प्रयोग है।

-bash$ hexdump test.dat 
0000000 01 bf f9 8b 00 00 00 00 04 00 00 00 01 00 00 00 
0000010 

मैं यह वास्तव में शामिल करने की उम्मीद:

-bash$ hexdump test.dat 
0000000 01 00 00 00 00 04 00 00 00 01 00 00 00 
0000010 

कीजिए newbiness

फ़ाइल के बाद मैं यह करने के लिए struct बारे में निम्नलिखित डेटा होता है। मैं सीखने की कोशिश कर रहा हूं :) मैं अपनी संरचना के डेटा घटकों को फ़ाइल में कुशलतापूर्वक कैसे लिखूं?

उत्तर

6

माइक्रोप्रोसेसर मनमाना पतों से डेटा लाने के लिए डिजाइन नहीं कर रहे हैं। वस्तुओं में इस तरह के 4 बाइट के रूप में int रों केवल चार से विभाज्य पतों पर संग्रहित किया जाना चाहिए। इस आवश्यकता को alignment कहा जाता है।

सी struct सदस्यों उन्हें संरेखित करने के लिए के बीच padding bytes डालने के लिए संकलक स्वतंत्रता देता है। पैडिंग की मात्रा विभिन्न प्लेटफॉर्म के बीच केवल एक चर है, एक और प्रमुख चर endianness है। यही कारण है कि यदि आप प्रोग्राम को एक से अधिक मशीनों पर चलाने के लिए चाहते हैं तो आपको डिस्क पर संरचनाओं को "डंप" नहीं करना चाहिए।

सर्वोत्तम अभ्यास प्रत्येक सदस्य को स्पष्ट रूप से लिखना है, और htonl का उपयोग बाइनरी आउटपुट से पहले बड़े-एंडियन को अंतहीनता को ठीक करने के लिए करना है। जब वापस पढ़ने, memcpy का उपयोग कच्चे बाइट्स स्थानांतरित करने के लिए,

char *buffer_ptr; 
... 
++ buffer_ptr; 
struct.member = * (int *) buffer_ptr; /* potential alignment error */ 

का उपयोग नहीं करते, लेकिन इसके बजाय

memcpy(buffer_ptr, (char *) & struct.member, sizeof struct.member); 
struct.member = ntohl(struct.member); /* if member is 4 bytes */ 
+0

इसके लिए धन्यवाद। तो मूल रूप से यह एक बाइट सरणी मैन्युअल रूप से बनाने और डिस्क पर लिखने के लिए नीचे आता है, फिर जब मैं इसे डिस्क से वापस पढ़ता हूं, उस सरणी से बाइट्स को एक नई आवंटित संरचना के सदस्यों में कॉपी करता हूं? मैं बस सचमुच सीख रहा हूं, लेकिन मैं इसे इस तरह से करना चाहूंगा जिसका मतलब यह होगा कि फाइल हमेशा मशीनों में समान प्रारूप रखने की गारंटी देती है, हां। – d11wtq

+1

@ d11wtq हाँ, सर्वोत्तम पोर्टेबिलिटी के लिए आपको सरणी से बाइट्स को प्रतिलिपि बनाने के लिए 'memcpy' का उपयोग करना चाहिए और फिर बाइट ऑर्डर को ठीक करने के लिए' ntohl' (या जो भी उचित है) पर कॉल करें। – Potatoswatter

+0

उत्कृष्ट, धन्यवाद। मेरे पास कुछ पढ़ने के लिए है। नौसिखिया होना मुश्किल है :) – d11wtq

1

करना जब आप संरचनाओं लिखने के रूप में fwrite, आप तो लिखा मिलता है के साथ है के रूप में वे स्मृति में हैं, struct कि गद्दी की वजह से डाला जाता है अंदर "मृत बाइट्स" भी शामिल है। इसके अतिरिक्त, आपके मल्टी-बाइट डेटा endiannes आपके सिस्टम की साथ लिखा है।

यदि आप ऐसा नहीं करना चाहते हैं, तो आपकी संरचना से डेटा क्रमबद्ध करें। आप केवल गैर-गद्दी वाले क्षेत्रों को लिख सकते हैं, और एक अनुमानित क्रम में मल्टीबाइट डेटा भी लिख सकते हैं (उदा। network byte order में)।

1

struct संरेखण नियम, जिसका अर्थ है उस में कुछ आइटम गद्देदार पाने के अधीन है।इसे देखकर, ऐसा लगता है कि पहले unsigned char फ़ील्ड को 4 बाइट्स तक पैड किया गया है।

यहां गठिया में से एक यह है कि नियम सिस्टम से सिस्टम से भिन्न हो सकते हैं, इसलिए यदि आप एक मंच पर एक कंपाइलर के साथ संकलित प्रोग्राम में fwrite का उपयोग करके संपूर्ण रूप से संरचना लिखते हैं, और फिर इसे पढ़ने का प्रयास करें fread दूसरे पर, आप कचरा प्राप्त कर सकते हैं क्योंकि दूसरा प्रोग्राम मान लेगा कि डेटा को स्ट्रक्चर लेआउट की अपनी अवधारणा को फिट करने के लिए गठबंधन किया गया है।

  1. तय है कि बचाया डेटा फ़ाइलों को ही मान्य अपने कार्यक्रम का हिस्सा है कि कुछ विशेषताओं (संकलक आप इस्तेमाल के दस्तावेज व्यवहार के आधार पर) के बनाता है के लिए कर रहे हैं, या

    :

    आम तौर पर, आप या तो करने के लिए है

  2. एक संपूर्ण संरचना को एक के रूप में नहीं लिखें, लेकिन एक अधिक औपचारिक डेटा प्रारूप लागू करें जहां प्रत्येक तत्व को स्पष्ट रूप से नियंत्रित आकार के साथ व्यक्तिगत रूप से लिखा गया हो।

(इससे संबंधित एक मुद्दा यह है कि बाइट क्रम अलग हो सकता है, एक ही विकल्प आम तौर पर विकल्प 2 में आप स्पष्ट रूप से डेटा स्वरूप की बाइट क्रम निर्दिष्ट करना चाहते हैं कि सिवाय भी वहाँ लागू होती है।)

+0

क्या बिंदु (2) के लिए अनुसरण करने के लिए कोई अच्छा पैटर्न है? मैं यहां जो कुछ भी करता हूं उसमें डिस्क I/O को कम करने की कोशिश कर रहा हूं (समयपूर्व अनुकूलन नहीं, लेकिन यह वास्तव में अभ्यास का बिंदु है ... मैं कम I/O ओवरहेड के साथ डिस्क पर डेटा सेट संग्रहीत करने के लिए पेड़ एल्गोरिदम की खोज कर रहा हूं , बस मज़ेदार के लिए। चार बार लिखना अक्षम होगा, इसलिए मुझे लगता है कि मुझे डेटा लिखने से पहले सी में किसी अन्य डेटा में कॉपी करना है? 'हस्ताक्षरित चार' प्रकारों की सरणी की तरह? – d11wtq

+0

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

+0

हां, यही वह है जो मैंने अंत में कर दिया, बाइट्स इन-मेमोरी को एक बफर में लिखने की तुलना में, धन्यवाद। – d11wtq

0

आप एक विशिष्ट प्रारूप में डेटा लिखने के लिए चाहते हैं, unsigned char की सरणी (रों) का उपयोग करें ...

unsigned char outputdata[13]; 
outputdata[0] = 1; 
outputdata[1] = 0; 
/* ... of course, use data from struct ... */ 
outputdata[12] = 0; 
fwrite(outputdata, sizeof outputdata, 1, fp); 
1

यह कुछ स्मृति संरेखण कहा जाता है की वजह से है। पहला चार स्मृति के 4 बाइट लेने के लिए बढ़ाया गया है। वास्तव में, int जैसे बड़े प्रकार 4 बाइट्स के ब्लॉक की शुरुआत में केवल "प्रारंभ" कर सकते हैं, इसलिए इस बिंदु तक पहुंचने के लिए बाइट्स के साथ कंपाइलर पैड।

मुझे 2 char से शुरू होने वाले बिटमैप हेडर के साथ एक ही समस्या थी। मैं struct के अंदर एक char bm[2] इस्तेमाल किया और 2 दिनों जहां # $%^3 और हेडर के 4 बाइट्स कहाँ जा ...

आप इसे रोकने के लिए चाहते हैं तो आप __attribute__((packed)) लेकिन beware, memory alignment IS necessary to your program to run conveniently उपयोग कर सकते हैं के लिए सोचा।

1

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

अपनी मेटाडेटा बाइट-बाय-बाइट एक ऐसी संरचना में लिखें जिसे गलत समझा नहीं जा सकता है। नल-समाप्त एएससीआईआई स्ट्रिंग ठीक है।

1

मैं ट्रॉय डी। हैंनसन द्वारा लिखित कोड का एक अद्भुत ओपन सोर्स टुकड़ा का उपयोग करता हूं जिसे टीपीएल: http://tpl.sourceforge.net/ कहा जाता है। टीपीएल के साथ आपके पास कोई बाहरी निर्भरता नहीं है। यह आपके स्वयं के कार्यक्रम में tpl.c और tpl.h सहित सरल है और टीपीएल एपीआई का उपयोग करें।

यहां मार्गदर्शिका है: http://tpl.sourceforge.net/userguide.html

+0

यह दिलचस्प लगता है, लेकिन मुझे लगता है मेरी विशेष जरूरतों के लिए यह अधिक होगा। मैं टी धारावाहिक डेटा में अपनी जानकारी जोड़कर डेटा के आकार को भी बढ़ाता है। मेरी फ़ाइल में एक सख्त प्रारूप होगा (प्रारंभिक शीर्षलेख के बाद एक बी-पेड़), इसलिए सिद्धांत में मैं फ़ाइल से डेटा को स्मृति में वापस कॉपी करने में सक्षम होना चाहिए, यह जानकर कि डेटा प्रकार क्या हैं। – d11wtq

+0

+1, दिलचस्प, लेकिन '.c' फ़ाइल समेत बाहरी निर्भरता की परिभाषा है। – Potatoswatter

+0

@Potatoswatter लाइसेंस आपको प्रोग्राम को फिर से वितरित करने की अनुमति देता है, इसलिए आपको tpl.c और tpl.h की आंतरिक निर्भरता में कोई समस्या नहीं है, आप अपने प्रोग्राम में बंडल कर सकते हैं। यह सच है कि यह मेटाडेटा और स्ट्रिंग डेटा प्रतिनिधित्व के कारण आकार को बढ़ाता है, लेकिन पोर्टेबिलिटी चिंता और तेज़ तैनाती निश्चित रूप से समस्याएं हो सकती हैं। – dAm2K