सूचना छिपाना
फ़ंक्शन के रिटर्न स्टेटमेंट में पूरी संरचना को वापस करने के विपरीत एक संरचना में सूचक को लौटने का क्या फायदा है?
सबसे आम एक जानकारी छिपाना है । C के पास struct
निजी क्षेत्र बनाने की क्षमता नहीं है, कहते हैं, उन्हें एक्सेस करने के लिए अकेले तरीके प्रदान करें।
इसलिए यदि आप डेवलपर्स को किसी पॉइंटर की सामग्री को देखने और छेड़छाड़ करने से रोकने के लिए मजबूर करना चाहते हैं, जैसे FILE
, तो एक और एकमात्र तरीका है कि वे पॉइंटर को अपारदर्शी के रूप में मानकर इसकी परिभाषा से अवगत होने से रोकें, जिसका पॉइंटर आकार बाहरी दुनिया के लिए परिभाषा अज्ञात है। FILE
तब वसीयत की परिभाषा केवल उन परिचालनों को लागू करने के लिए दृश्यमान होगी, जिन्हें इसकी परिभाषा की आवश्यकता होती है, जैसे fopen
, जबकि केवल संरचना घोषणा सार्वजनिक शीर्ष लेख को दिखाई देगी।
बाइनरी संगतता
संरचना की परिभाषा को छिपाने से डायलीब एपीआई में द्विआधारी संगतता को बनाए रखने के लिए सांस लेने में मदद मिल सकती है। यह पुस्तकालय कार्यान्वयनकर्ताओं को पुस्तकालय का उपयोग करने वालों के साथ द्विआधारी संगतता को तोड़ने के बिना अपारदर्शी संरचना में फ़ील्ड्स को बदलने की अनुमति देता है, क्योंकि उनके कोड की प्रकृति को केवल यह जानना है कि वे संरचना के साथ क्या कर सकते हैं, न कि यह कितना बड़ा है या क्या फ़ील्ड है। यह है।
एक उदाहरण के रूप में, मैं वास्तव में विंडोज 95 युग के दौरान बनाए गए कुछ प्राचीन कार्यक्रमों को आज चला सकता हूं (हमेशा पूरी तरह से नहीं, लेकिन आश्चर्यजनक रूप से कई अभी भी काम करते हैं)। संभावना है कि उन प्राचीन बायनेरिज़ के लिए कुछ कोड उन संरचनाओं के लिए अपारदर्शी बिंदुओं का उपयोग करते थे जिनके आकार और सामग्री विंडोज 95 युग से बदल गई हैं। फिर भी कार्यक्रम विंडोज़ के नए संस्करणों में काम करना जारी रखते हैं क्योंकि वे उन संरचनाओं की सामग्री के संपर्क में नहीं थे। जब एक पुस्तकालय पर काम करना जहां द्विआधारी संगतता महत्वपूर्ण है, तो जो ग्राहक उजागर नहीं होता है उसे आम तौर पर पीछे की संगतता को तोड़ने के बिना बदलने की अनुमति दी जाती है।
दक्षता
एक पूर्ण संरचना लौटना जो कि NULL है, मैं कठिन या कम कुशल होगा। क्या यह एक वैध कारण है?
यह आम तौर पर कम कुशल है, यह मानते हुए कि प्रकार को व्यावहारिक रूप से फिट किया जा सकता है और स्टैक पर आवंटित किया जा सकता है जब तक कि आम तौर पर पर्दे के पीछे इस्तेमाल किए जाने वाले सामान्यीकृत मेमोरी आवंटन की malloc
तरह नहीं होता , जैसे कि पहले से आवंटित चर-आकार के आवंटन पूलिंग मेमोरी के बजाय एक निश्चित आकार। यह इस मामले में एक सुरक्षा व्यापार बंद है, सबसे अधिक संभावना है, पुस्तकालय डेवलपर्स को संबंधित से संबंधित वैचारिक (वैचारिक गारंटी) बनाए रखने की अनुमति देता है FILE
।
यह कम से कम एक प्रदर्शन के दृष्टिकोण से fopen
एक पॉइंटर को वापस करने के लिए ऐसा कोई वैध कारण नहीं है क्योंकि यह एकमात्र कारण है जो NULL
किसी फ़ाइल को खोलने में विफलता पर है। यह सभी सामान्य-मामले निष्पादन मार्गों को धीमा करने के बदले में एक असाधारण परिदृश्य का अनुकूलन होगा। कुछ मामलों में मान्य उत्पादकता का कारण हो सकता है कि वे डिज़ाइन को अधिक सीधा बनाने के लिए उन्हें NULL
कुछ पोस्ट-स्थिति पर वापस लौटने की अनुमति देने के लिए वापसी बिंदु बनाते हैं।
फ़ाइल संचालन के लिए, ओवरहेड फ़ाइल के संचालन की तुलना में अपेक्षाकृत अधिक तुच्छ है, और मैनुअल को fclose
किसी भी तरह से टाला नहीं जा सकता है। इसलिए ऐसा नहीं है कि हम ग्राहक को परिभाषा को मुक्त करने (बंद करने) की परेशानी से बचा सकते हैं FILE
और परिभाषा को उजागर fopen
कर सकते हैं या एक ढेर आवंटन से बचने के लिए फ़ाइल के संचालन की सापेक्ष लागत को देखते हुए बहुत अधिक प्रदर्शन को बढ़ावा देने की उम्मीद करते हैं। ।
हॉटस्पॉट्स और फिक्सेस
अन्य मामलों के लिए, हालांकि, मैंने हॉटस्पॉट्स के साथ विरासत कोडबेस में बहुत सारे फालतू सी कोड की रूपरेखा तैयार की है malloc
और अनावश्यक अभ्यास कैश के रूप में इस अभ्यास के परिणामस्वरूप अक्सर अपारदर्शी बिंदुओं के साथ और ढेर पर बहुत सी चीजों को आवंटित करने के परिणामस्वरूप चूक जाता है। बड़े छोरों।
इसके बजाय मैं जो वैकल्पिक अभ्यास करता हूं वह संरचना परिभाषाओं को उजागर करने के लिए है, भले ही क्लाइंट उन्हें छेड़छाड़ करने के लिए न हो, एक कन्वेंशन नामकरण मानक का उपयोग करके यह बताता है कि किसी और को खेतों को नहीं छूना चाहिए:
struct Foo
{
/* priv_* indicates that you shouldn't tamper with these fields! */
int priv_internal_field;
int priv_other_one;
};
struct Foo foo_create(void);
void foo_destroy(struct Foo* foo);
void foo_something(struct Foo* foo);
यदि भविष्य में द्विआधारी संगतता चिंताएं हैं, तो मैंने इसे बहुत बेहतर पाया है ताकि भविष्य के प्रयोजनों के लिए कुछ अतिरिक्त स्थान आरक्षित कर सकें, जैसे:
struct Foo
{
/* priv_* indicates that you shouldn't tamper with these fields! */
int priv_internal_field;
int priv_other_one;
/* reserved for possible future uses (emergency backup plan).
currently just set to null. */
void* priv_reserved;
};
यह आरक्षित स्थान थोड़ा व्यर्थ है, लेकिन भविष्य में अगर हम Foo
अपने पुस्तकालय का उपयोग करने वाले बायनेरिज़ को तोड़ने के बिना कुछ और डेटा जोड़ने की आवश्यकता है, तो हम एक जीवन रक्षक हो सकते हैं ।
मेरी राय में जानकारी को छिपाना और बाइनरी संगतता आमतौर पर केवल सभ्य कारण है जो केवल वैरिएबल-लेंथ स्ट्रक्चर के अलावा संरचनाओं के ढेर आवंटन की अनुमति देता है (जिसे हमेशा इसकी आवश्यकता होगी, या कम से कम थोड़ा उपयोग करने के लिए अजीब होना चाहिए अन्यथा क्लाइंट को आवंटित करना था वीएलएस आवंटित करने के लिए एक वीएलए फैशन में स्टैक पर मेमोरी)। यहां तक कि बड़ी संरचनाएं अक्सर मूल्य से लौटने के लिए सस्ती होती हैं यदि इसका मतलब है कि सॉफ़्टवेयर स्टैक पर गर्म मेमोरी के साथ बहुत अधिक काम कर रहा है। और भले ही वे निर्माण पर मूल्य द्वारा वापस जाने के लिए सस्ता नहीं थे, एक बस यह कर सकता है:
int foo_create(struct Foo* foo);
...
/* In the client code: */
struct Foo foo;
if (foo_create(&foo))
{
foo_something(&foo);
foo_destroy(&foo);
}
... Foo
एक शानदार प्रतिलिपि की संभावना के बिना स्टैक से आरंभ करने के लिए । या ग्राहक को भी Foo
ढेर पर आवंटित करने की स्वतंत्रता है अगर वे किसी कारण से चाहते हैं।