2010-01-04 11 views
47

Win32 एपीआई प्रोग्रामिंग में यह कई क्षेत्रों के साथ सी struct एस का उपयोग करने के लिए विशिष्ट है। आम तौर पर उनमें से केवल कुछ में सार्थक मूल्य होते हैं और अन्य सभी को शून्य करना पड़ता है। यह दो तरीकों में से किसी हासिल किया जा सकता:मेमसेट() या एक संरचना को शून्य करने के लिए मूल्य प्रारंभिकरण?

STRUCT theStruct; 
memset(&theStruct, 0, sizeof(STRUCT)); 

या

STRUCT theStruct = {}; 

दूसरा संस्करण क्लीनर लग रहा है - यह एक एक लाइनर है, यह कोई पैरामीटर है कि गलत टाइप किया जा सकता है नहीं है और लगाए जा रहे एक त्रुटि का कारण बनता है।

क्या पहले संस्करण की तुलना में इसमें कोई कमी है? उपयोग करने के लिए कौन सा संस्करण और क्यों?

+0

यह [जवाब] [1] बाद में एक प्रश्न के और अधिक उपयोगी और आसान प्रतीत होता है। [1]: http://stackoverflow.com/questions/4625212/class-initialization-list/4625730#4625730 – TheMatto

उत्तर

73

उन दो निर्माणों एक बहुत उनके अर्थ में अलग है। पहले एक एक memset समारोह है, जो करने का इरादा है निश्चित मूल्य को स्मृति का एक बफर सेट का उपयोग करता है। दूसरा एक ऑब्जेक्ट प्रारंभ करें। मुझे कोड का एक सा के साथ यह स्पष्ट करने दें:

चलो मान लेते हैं तो आप एक संरचना केवल पॉड प्रकार

struct POD_OnlyStruct 
{ 
    int a; 
    char b; 
}; 

POD_OnlyStruct t = {}; // OK 

POD_OnlyStruct t; 
memset(&t, 0, sizeof t); // OK as well 

इस मामले में एक POD_OnlyStruct t = {} या POD_OnlyStruct t; memset(&t, 0, sizeof t) ज्यादा फर्क नहीं है लिखने की है कि सदस्य , जैसा कि हमारे पास एकमात्र अंतर है, संरेखण बाइट memset के मामले में शून्य-मान पर सेट किया जा रहा है। चूंकि आपके पास सामान्य रूप से उन बाइट्स तक पहुंच नहीं है, इसलिए आपके लिए कोई अंतर नहीं है।

दूसरी ओर, आप सी ++ के रूप में अपने प्रश्न टैग किया है के बाद से, के पॉड से प्रकार अलग-अलग सदस्य के साथ एक और उदाहरण की कोशिश, चलो: एक अभिव्यक्ति का उपयोग कर TestStruct t = {} की तरह अच्छा है

struct TestStruct 
{ 
    int a; 
    std::string b; 
}; 

TestStruct t = {}; // OK 

{ 
    TestStruct t1; 
    memset(&t1, 0, sizeof t1); // ruins member 'b' of our struct 
} // Application crashes here 

इस मामले में , और memset का उपयोग करके यह क्रैश हो जाएगा। यहां बताया गया है कि यदि आप memset का उपयोग करते हैं तो TestStruct का एक ऑब्जेक्ट बनाया गया है, इस प्रकार यह std::string प्रकार का ऑब्जेक्ट बना रहा है, क्योंकि यह हमारी संरचना का सदस्य है। अगला, memset स्मृति सेट करता है जहां ऑब्जेक्ट b कुछ मान पर स्थित था, शून्य कहें। अब, जब हमारी टेस्टस्ट्रक्चर ऑब्जेक्ट गुंजाइश से बाहर हो जाती है, तो इसे नष्ट किया जा रहा है और जब इसकी बारी std::string b पर आती है तो आपको एक क्रैश दिखाई देगा, क्योंकि उस ऑब्जेक्ट की आंतरिक संरचनाओं को memset द्वारा बर्बाद कर दिया गया था।

तो, वास्तविकता यह है, उन चीजों बहुत अलग हैं, और हालांकि आप कभी कभी memset को कुछ मामलों में शून्य करने के लिए एक पूरी संरचना की जरूरत है, यह हमेशा सुनिश्चित करें कि आप समझते हैं कि आप क्या कर रहे हैं बनाने के लिए महत्वपूर्ण है, और नहीं हमारे दूसरे उदाहरण में गलती करें।

मेरा वोट - वस्तुओं पर memset का उपयोग केवल यदि यह आवश्यक है, और अन्य सभी मामलों में डिफ़ॉल्ट प्रारंभ x = {} का उपयोग करें।

+0

हाय आयाम!मेरे पास एक संरचना है जिसमें कुछ सदस्य हैं और मैंने memsetting के पहले विकल्प की कोशिश की: "struct stvar = {}"। लेकिन मुझे "-मिंग-फील्ड-प्रारंभिक" चेतावनी मिल रही है। क्या यह एक मुद्दा है? – MayurK

+0

इस मामले में, * पीओडी * द्वारा आपका मतलब वास्तव में एक * तुच्छ रूप से रचनात्मक * वस्तु है (यानी उपयोगकर्ता द्वारा प्रदत्त सी-टोर के बिना ऑब्जेक्ट)? मुझे नहीं लगता कि इसे पीओडी को बाध्य किया जाना चाहिए। –

6

मैं मूल्य प्रारंभिकरण का उपयोग करूंगा क्योंकि यह आपके द्वारा उल्लिखित स्वच्छ और कम त्रुटि प्रवण दिखता है। मुझे ऐसा करने में कोई कमी नहीं दिख रही है।

हालांकि आप उपयोग किए जाने के बाद संरचना को शून्य करने के लिए memset पर भरोसा कर सकते हैं।

5

यह नहीं कि यह आम है, लेकिन मुझे लगता है कि दूसरे तरीके से फ्लोट को शून्य पर प्रारंभ करने का लाभ भी है। एक मेमसेट करने के दौरान निश्चित रूप से

+0

'जबकि निश्चित रूप से not' होगा एक memset कर - पूरी तरह सच नहीं। दरअसल, x86 और x64 पर एक फ्लोट/डबल से शून्य को याद करने पर इसे शून्य पर सेट कर दिया जाएगा। निश्चित रूप से, यह सी/सी ++ मानक में नहीं है, लेकिन यह सबसे लोकप्रिय प्लेटफॉर्म पर काम करता है। – sbk

+2

एसबीके: अभी के लिए ... कौन जानता है कि फ़्लोटिंग पॉइंट कार्यान्वयन का उपयोग करना शुरू हो सकता है। आईईईई 754 संकलक के लिए परिभाषित नहीं है। तो अगर यह अब भी काम कर सकता है, तो यह आपके लिए सिर्फ भाग्यशाली है, लेकिन बाद में समस्याएं दे सकता है। – Toad

2

मूल्य प्रारंभिकता क्योंकि यह संकलन समय पर किया जा सकता है।
यह भी सही ढंग से 0 सभी पीओडी प्रकारों को शुरू करता है।

मेमसेट() रनटाइम पर किया जाता है।
मेमसेट() का भी उपयोग करना संदिग्ध है यदि संरचना पीओडी नहीं है।
गैर इंट प्रकारों को सही ढंग से प्रारंभ नहीं किया जाता है।

+3

संकलन समय पर मूल्य प्रारंभ नहीं किए गए हैं। कंपाइलर स्टार्टअप कोड उत्पन्न करता है जो कार्यक्रम के दौरान सभी ग्लोबल्स शुरू करता है इस प्रकार रनटाइम पर शुरू होता है। स्टैक चर के लिए प्रारंभिककरण फ़ंक्शन एंट्री पर किया जाता है - फिर रनटाइम पर। – qrdl

+0

@qrdl, संकलक और लक्ष्य पर निर्भर करता है। रोम-सक्षम कोड के लिए, मान कभी-कभी संकलन समय पर सेट होते हैं। –

+2

@qrdl: मुझे दोबारा वाक्यांश दो। वैल्यू प्रारंभिक संकलन (कुछ स्थितियों के तहत) संकलक को संकलन समय (रन-टाइम के बजाए) प्रारंभ करने के लिए अनुमति दे सकता है। तो पीओडी केवल ग्लोबल्स संकलन समय पर शुरू किया जा सकता है। –

28

संरचना सदस्यों के आधार पर, दो प्रकार आवश्यक नहीं हैं। memset संरचना को सभी बिट्स-शून्य पर सेट करेगा जबकि मूल्य प्रारंभिकता सभी सदस्यों को मान शून्य पर प्रारंभ करेगी। सी मानक इन्हें केवल अभिन्न प्रकारों के लिए ही गारंटी देता है, न कि फ्लोटिंग-पॉइंट मानों या पॉइंटर्स के लिए।

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

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

+0

, किस प्लेटफॉर्म पर ज़ीरो के लिए सभी बिट्स के साथ एक फ्लोट सकारात्मक शून्य नहीं है? –

+3

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

+1

कोई फर्क नहीं पड़ता। सी मानक निर्दिष्ट नहीं करता कि फ्लोट प्रारूप का उपयोग किस प्रकार किया जाता है। तो भले ही वह आईईईई 754 के लिए अब काम करता है, यह एक अलग नाव कार्यान्वयन (भविष्य या अतीत) – Toad

-1

यदि बहुत सारे पॉइंटर सदस्य हैं और आप भविष्य में और अधिक जोड़ने की संभावना रखते हैं, तो यह मेमसेट का उपयोग करने में मदद कर सकता है। उपयुक्त assert(struct->member) कॉल के साथ संयुक्त आप यादृच्छिक क्रैश से बचने के लिए एक खराब सूचक को समझने से बच सकते हैं जिसे आप प्रारंभ करना भूल गए थे। लेकिन अगर आप मेरे जैसे भूल जाते हैं, तो सदस्य-प्रारंभिक शायद सबसे अच्छा है!

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

+0

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

+0

साथ ही, यदि संरचना सार्वजनिक एपीआई का हिस्सा है, तो हो सकता है कि किसी को इसके बजाय प्रारंभिक कार्य के साथ एक अपारदर्शी संरचना पर विचार करना चाहिए। – jamesdlin

3

कुछ कंपाइलर्स में STRUCT theStruct = {}; निष्पादन योग्य में memset(&theStruct, 0, sizeof(STRUCT)); का अनुवाद करेगा। कुछ सी फ़ंक्शंस पहले ही रनटाइम सेटअप करने के लिए जुड़े हुए हैं, इसलिए कंपाइलर में इन लाइब्रेरी फ़ंक्शंस जैसे मेमसेट/मेम्पी का उपयोग करने के लिए उपलब्ध है।

+1

यह वास्तव में मुझे हाल ही में थोड़ा मुश्किल है। मैं संपीड़न कोड के एक कस्टम टुकड़े पर काम कर रहा था और 'संरचना कुछ foo = {x, y, z}' का उपयोग करके घोषणा समय पर कुछ बड़े ढांचे को शुरू कर रहा था और कैश्रिंड ने दिखाया कि मेरे कार्यक्रम के "काम" का 70% 'स्मृति' में था क्योंकि प्रत्येक फंक्शन कॉल पर structs शून्य थे। –

10

अपने struct तरह बातें शामिल हैं:

int a; 
char b; 
int c; 

फिर गद्दी के बाइट्स "बी" और "सी" के बीच सम्मिलित किया जाएगा। memset() उनको शून्य कर देगा, दूसरा तरीका नहीं होगा, इसलिए कचरे के 3 बाइट होंगे (यदि आपकी चींटियां 32 बिट्स हैं)। यदि आप किसी फ़ाइल से पढ़ने/लिखने के लिए अपनी संरचना का उपयोग करना चाहते हैं, तो यह महत्वपूर्ण हो सकता है।

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