सी में NULL के लिए पॉइंटर्स कब चेक किए जाने चाहिए?


18

सारांश :

C में एक फ़ंक्शन को हमेशा यह सुनिश्चित करने के लिए जांचना चाहिए कि यह एक NULLपॉइंटर को डीरफेरिंग नहीं कर रहा है ? यदि नहीं, तो इन जाँचों को कब छोड़ना उचित है?

विवरण :

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

उदाहरण के लिए git के स्रोत कोड में निम्नलिखित प्रकट होता है:

static unsigned short graph_get_current_column_color(const struct git_graph *graph)
{
    if (!want_color(graph->revs->diffopt.use_color))
        return column_colors_max;
    return graph->default_column_color;
}

अगर *graphहै NULLतो एक अशक्त सूचक dereferenced किया जाएगा, शायद कार्यक्रम दुर्घटनाग्रस्त, लेकिन संभवतः कुछ अन्य अप्रत्याशित व्यवहार में जिसके परिणामस्वरूप। दूसरी ओर फ़ंक्शन है staticऔर इसलिए शायद प्रोग्रामर ने पहले से ही इनपुट को मान्य किया है। मुझे नहीं पता, मैंने इसे यादृच्छिक रूप से चुना क्योंकि यह सी में लिखे गए एक एप्लिकेशन प्रोग्राम में एक छोटा उदाहरण था। मैंने कई अन्य स्थानों पर देखा है, जहां NULL की जाँच किए बिना पॉइंटर्स का उपयोग किया जाता है। मेरा प्रश्न इस कोड सेगमेंट के लिए सामान्य नहीं है।

मैंने अपवाद स्वरूप सौंपने के संदर्भ में एक समान प्रश्न पूछा । हालांकि, सी या सी ++ जैसी असुरक्षित भाषा के लिए, बिना किसी अपवाद के कोई स्वचालित त्रुटि प्रसार नहीं है।

दूसरी ओर मैंने ओपन सोर्स प्रोजेक्ट्स (जैसे ऊपर उदाहरण) में बहुत सारे कोड देखे हैं, जो उन्हें इस्तेमाल करने वाले पॉइंटर्स का कोई चेक नहीं करता है। मैं सोच रहा था कि किसी को दिशा-निर्देशों पर विचार करना है कि किसी फ़ंक्शन में चेक कब डालना है या यह मानकर कि फ़ंक्शन को सही तर्क के साथ कहा गया था।

मैं उत्पादन कोड लिखने के लिए सामान्य रूप से इस सवाल में दिलचस्पी लेता हूं। लेकिन मुझे इंटरव्यू प्रोग्रामिंग इंटरव्यू के संदर्भ में भी है। उदाहरण के लिए कई एल्गोरिथ्म पाठ्यपुस्तकें (जैसे सीएलआर) एल्गोरिदम को बिना किसी त्रुटि जाँच के छद्मकोश में प्रस्तुत करने की प्रवृत्ति रखते हैं। हालांकि, जबकि यह एक एल्गोरिथ्म के मूल को समझने के लिए अच्छा है, यह स्पष्ट रूप से एक अच्छा प्रोग्रामिंग अभ्यास नहीं है। इसलिए मैं एक साक्षात्कारकर्ता को यह बताना नहीं चाहूंगा कि मैं अपने कोड उदाहरणों को सरल बनाने के लिए त्रुटि की जाँच कर रहा था (जैसा कि एक पाठ्यपुस्तक हो सकती है)। लेकिन मैं भी अत्यधिक त्रुटि जाँच के साथ अक्षम कोड का उत्पादन करना नहीं चाहता हूँ। उदाहरण के लिए, अशक्त के graph_get_current_column_colorलिए जाँच करने के *graphलिए संशोधित किया जा सकता था, लेकिन यह स्पष्ट नहीं है कि यदि *graphयह अशक्त होगा, तो इसके अलावा यह इसे नहीं करना चाहिए।


7
यदि आप एक एपीआई के लिए एक फ़ंक्शन लिख रहे हैं, जहां कॉल करने वालों को सराय समझने की जरूरत नहीं है, तो यह उन स्थानों में से एक है जहां प्रलेखन महत्वपूर्ण है। यदि आप यह दस्तावेज़ करते हैं कि एक तर्क एक वैध, गैर-पूर्ण सूचक होना चाहिए, तो यह जांचना कॉलर की जिम्मेदारी बन जाती है।
Blrfl


2017 के वर्ष की बाधा के साथ, 2013 को प्रश्न और अधिकांश उत्तरों को ध्यान में रखते हुए, क्या उत्तरदाताओं में से कोई भी उत्तर संकलनकर्ताओं के अनुकूलन के कारण समय-यात्रा के अपरिभाषित व्यवहार के मुद्दे को संबोधित करता है ?
rwong

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

जवाबों:


15

अमान्य नल बिंदु या तो प्रोग्रामर त्रुटि या रनटाइम त्रुटि के कारण हो सकते हैं। रनटाइम त्रुटियाँ कुछ ऐसी हैं जिन्हें प्रोग्रामर ठीक नहीं कर सकता है, जैसे mallocकि कम मेमोरी के कारण फेल होना या किसी पैकेट को छोड़ने वाला नेटवर्क या उपयोगकर्ता का कुछ बेवकूफ होना। प्रोग्रामर त्रुटियां एक प्रोग्रामर द्वारा गलत तरीके से फ़ंक्शन का उपयोग करने के कारण होती हैं।

अंगूठे का सामान्य नियम मैंने देखा है कि रनटाइम त्रुटियों की हमेशा जांच की जानी चाहिए, लेकिन प्रोग्रामर त्रुटियों को हर बार जांचना आवश्यक नहीं है। मान लें कि कुछ बेवकूफ प्रोग्रामर को सीधे बुलाया जाता है graph_get_current_column_color(0)। यह पहली बार कहा जाता है कि यह segfault होगा, लेकिन एक बार जब आप इसे ठीक कर लेते हैं, तो फिक्स को स्थायी रूप से संकलित किया जाता है। इसे चलाने के लिए हर बार जांचने की आवश्यकता नहीं है।

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

जाहिर है, आप हमेशा किसी को अधिक पा सकते हैं, लेकिन अधिकांश सी प्रोग्रामर मुझे पता है कि कोड पर कम क्लॉट किए गए कोड का पक्ष है जो कि मामूली सुरक्षित है। और "सुरक्षित" एक व्यक्तिपरक शब्द है। क्षेत्र में सूक्ष्म भ्रष्टाचार के विकास के दौरान विकास के दौरान एक गंभीर बदलाव होना बेहतर होता है।


सवाल कुछ व्यक्तिपरक है लेकिन यह अब के लिए सबसे अच्छा जवाब की तरह लग रहा था। इस सवाल पर अपने विचार देने वाले सभी को धन्यवाद।
गैब्रियल दक्षिणी

1
IOS में, Malloc कभी भी NULL नहीं लौटेगा। यदि यह कोई मेमोरी नहीं पाता है, तो यह आपके एप्लिकेशन को पहले मेमोरी जारी करने के लिए कहेगा, फिर यह ऑपरेटिंग सिस्टम से पूछता है (जो अन्य ऐप्स को मेमोरी रिलीज़ करने और संभवतः उन्हें मारने के लिए कहेंगे), और अगर कोई मेमोरी नहीं है, तो यह आपके ऐप को मार देगा । कोई जांच की जरूरत नहीं है।
gnasher729

11

"सॉफ्टवेयर टूल्स" में केर्निघन एंड प्लॉजर ने लिखा है कि वे सब कुछ जांचेंगे, और, उन स्थितियों के लिए जो उन्हें विश्वास था कि वास्तव में ऐसा कभी नहीं होगा, वे एक त्रुटि संदेश "नहीं हो सकते" के साथ गर्भपात करेंगे।

वे रिपोर्ट करते हैं कि उनके टर्मिनलों पर जितनी बार देखा जा सकता है उतनी तेजी से "" नहीं "" हो सकता है।

आपको अपने से पहले इसे हटाने के लिए NULL के लिए पॉइंटर को चेक करना चाहिए (प्रयास करना)। हमेशा । NULL के लिए आपके द्वारा डुप्लिकेट की गई कोडिंग की मात्रा, जो नहीं होती है, और प्रोसेसर आपको "बेकार" करता है, क्रैश क्रैश की संख्या से अधिक भुगतान के लिए होगा जो आपको क्रैश डंप से अधिक कुछ नहीं से डीबग करना होगा - अगर तुम भाग्यशाली हो

यदि पॉइंटर एक लूप के अंदर अपरिवर्तनीय है, तो यह लूप के बाहर की जाँच करने के लिए पर्याप्त है, लेकिन आपको लूप द्वारा उपयोग के लिए इसे एक स्कोप-सीमित स्थानीय चर में "कॉपी" करना चाहिए, जो उचित कॉस्ट डेकोरेशन जोड़ता है। इस स्थिति में, आप यह सुनिश्चित करना चाहते हैं कि लूप बॉडी से बुलाए गए प्रत्येक फ़ंक्शन में प्रोटोटाइप पर आवश्यक कास्ट डेकोरेशन, ऑल द वे वॉट शामिल हैं। आप नहीं करते हैं, या नहीं कर सकते हैं (क्योंकि जैसे एक विक्रेता पैकेज या एक जिद्दी सहकर्मी की), तो आप शून्य के लिए यह जांच करना चाहिए हर बार संशोधित किया जा सकता है , क्योंकि यकीन है कि के रूप में कर्नल मर्फी एक लाइलाज आशावादी था, किसी को है जा रहा जब आप नहीं देख रहे हैं तो इसे zap करें।

यदि आप किसी फ़ंक्शन के अंदर हैं, और पॉइंटर को गैर-NULL होना माना जाता है, तो आपको इसे सत्यापित करना चाहिए।

यदि आप इसे किसी फंक्शन से प्राप्त कर रहे हैं, और यह नॉन-न्यूल से बाहर आने वाला है, तो आपको इसे सत्यापित करना चाहिए। मॉलोक () इसके लिए विशेष रूप से कुख्यात है। (नॉर्टेल नेटवर्क, अब दोषपूर्ण है, इस बारे में एक कठिन और तेज़ लिखित कोडिंग मानक था। मुझे एक बिंदु पर दुर्घटना का सामना करना पड़ा, कि मैं वापस मालॉक पर लौट आया) (एक पूर्ण सूचक को लौटाने और बेवकूफ कोडर जाँच करने के लिए परेशान कर रहा था। इससे पहले कि उसने इसे लिखा, क्योंकि वह सिर्फ KNEW था, उसकी बहुत स्मृति थी ... मैंने कुछ बहुत ही गंदी बातें कही जब आखिरकार इसे समाप्त कर दिया।)


8
यदि आप एक ऐसे फ़ंक्शन में हैं जिसके लिए एक गैर-NULL पॉइंटर की आवश्यकता होती है, लेकिन आप वैसे भी जाँच करते हैं और यह NULL ... आगे क्या है?
detly

1
@ या तो रोकें कि आप क्या कर रहे हैं और एक त्रुटि कोड लौटाएं, या एक अभिकर्मक यात्रा करें
जेम्स

1
@ जेम्स - assertनिश्चित रूप से नहीं सोचा था । यदि आप NULLचेक को शामिल करने के लिए मौजूदा कोड को बदलने की बात कर रहे हैं तो मुझे त्रुटि कोड विचार पसंद नहीं है ।
2

10
अगर आप त्रुटि कोड पसंद नहीं करते हैं तो @detly आपको सी देव के रूप में बहुत दूर नहीं जाना है
जेम्स

5
@ JohnR.Strohm - यह C है, यह दावा या कुछ भी नहीं है: P
detly

5

आप चेक को तब छोड़ सकते हैं जब आप किसी तरह खुद को समझा सकते हैं कि पॉइंटर संभवतः अशक्त नहीं हो सकता है।

आमतौर पर, नल पॉइंटर चेक को कोड में लागू किया जाता है, जिसमें नल को एक संकेतक के रूप में दिखाई देने की उम्मीद है कि एक वस्तु वर्तमान में उपलब्ध नहीं है। नल का उपयोग एक प्रहरी मूल्य के रूप में किया जाता है, उदाहरण के लिए लिंक की गई सूचियों को समाप्त करने के लिए, या बिंदुओं के सरणियों के लिए भी। argvमें पारित कर दिया तार के वेक्टर mainएक सूचक द्वारा होना आवश्यक है अशक्त-समाप्त, इसी तरह कैसे एक स्ट्रिंग एक अशक्त चरित्र से समाप्त हो जाता है करने के लिए: argv[argc]एक अशक्त सूचक है, और आप जब आदेश पंक्ति को पार्स इस पर भरोसा कर सकते हैं।

while (*argv) {
   /* process argument string *argv */
   argv++; /* increment to next one */
}

तो, अशक्त के लिए जाँच करने की स्थितियाँ वे हैं जिनमें यह एक अपेक्षित मूल्य है। अशक्त चेक अशक्त सूचक के अर्थ को कार्यान्वित करते हैं, जैसे कि लिंक की गई सूची की खोज को रोकना। वे कोड को पॉइंफ्रेंसिंग से सूचक को रोकते हैं।

ऐसी स्थिति में जिसमें एक शून्य सूचक मूल्य डिजाइन द्वारा अपेक्षित नहीं है, इसके लिए जाँच करने का कोई मतलब नहीं है। यदि कोई अमान्य पॉइंटर मान उत्पन्न होता है, तो यह संभवतः गैर-अशक्त दिखाई देगा, जिसे किसी भी पोर्टेबल तरीके से मान्य मानों से अलग नहीं किया जा सकता है। उदाहरण के लिए, एक सूचक मान को पढ़ने के लिए प्राप्त किया गया, जो कि अनइंस्टाल्यूटेड स्टोरेज के रूप में समझा जाता है, एक पॉइंटर प्रकार, कुछ छाया रूपांतरण के माध्यम से प्राप्त एक पॉइंटर, या एक पॉइंटर सीमा से बाहर बढ़ा हुआ।

डेटा प्रकार के बारे में जैसे graph *: इसे इसलिए डिज़ाइन किया जा सकता है ताकि एक शून्य मान एक मान्य ग्राफ़ हो: जिसमें कोई किनारा न हो और कोई नोड न हो। इस स्थिति में, graph *पॉइंटर लेने वाले सभी कार्यों को उस मूल्य से निपटना होगा, क्योंकि यह ग्राफ़ के प्रतिनिधित्व में एक सही डोमेन मूल्य है। दूसरी ओर, एक graph *कंटेनर जैसी वस्तु के लिए एक संकेतक हो सकता है जो एक ग्राफ रखने पर कभी भी अशक्त नहीं होता है; null पॉइंटर तब हमें बता सकता है कि "ग्राफ़ ऑब्जेक्ट मौजूद नहीं है; हमने इसे अभी तक आवंटित नहीं किया है, या इसे मुक्त नहीं किया है; या वर्तमान में इसका कोई संबद्ध ग्राफ़ नहीं है"। पॉइंटर्स का यह उत्तरार्द्ध उपयोग एक संयुक्त बूलियन / उपग्रह है: पॉइंटर नॉन-नल होने का संकेत "मेरे पास इस बहन वस्तु" है, और यह उस वस्तु को प्रदान करता है।

हम एक सूचक को शून्य करने के लिए सेट कर सकते हैं, भले ही हम किसी वस्तु को मुक्त न कर रहे हों, बस एक वस्तु को दूसरे से अलग करने के लिए:

tty_driver->tty = NULL; /* detach low level driver from the tty device */

सबसे ठोस तर्क मुझे पता है कि एक सूचक एक निश्चित बिंदु पर शून्य नहीं हो सकता है, उस बिंदु को "अगर (ptr! = NULL) {" और इसी "}" में लपेटना है। इसके अलावा, आप औपचारिक सत्यापन क्षेत्र में हैं।
जॉन आर। स्ट्रॉहेम

4

मुझे एक और आवाज फगुआ में जोड़ने की।

अन्य जवाबों में से कई की तरह, मैं कहता हूं - इस बिंदु पर जाँच करने से परेशान न हों; यह कॉलर की जिम्मेदारी है। लेकिन मेरे पास सरल अभियान (और सी प्रोग्रामिंग अहंकार) के बजाय निर्माण की नींव है।

मैं डोनाल्ड नुथ के प्रमुख कार्यक्रमों को यथासंभव नाजुक बनाने की कोशिश करता हूं। अगर कुछ भी गलत होता है, तो यह बड़ा दुर्घटनाग्रस्त होता है , और एक अशक्त सूचक को संदर्भित करना आमतौर पर ऐसा करने का एक अच्छा तरीका है। सामान्य विचार एक दुर्घटना है या एक अनंत लूप गलत डेटा बनाने से कहीं बेहतर है। और इसे प्रोग्रामर्स का ध्यान जाता है!

लेकिन अशक्त संकेत (विशेष रूप से बड़ी डेटा संरचनाओं के लिए) को संदर्भित करना हमेशा दुर्घटना का कारण नहीं बनता है। आह। यह सच है। और यही वह जगह है जहाँ एसेर्ट्स गिरते हैं। वे सरल होते हैं, तुरंत आपके प्रोग्राम को क्रैश कर सकते हैं (जो सवाल का जवाब देता है, "अगर यह एक अशक्तता का सामना करता है तो क्या करना चाहिए?"), और विभिन्न स्थितियों के लिए चालू / बंद किया जा सकता है (मैं सलाह देता हूं) उन्हें बंद न करें, क्योंकि ग्राहकों के लिए क्रैश होना और खराब डेटा की तुलना में एक गुप्त संदेश देखना बेहतर है)।

वह मेरा दो सेंट है।


1

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

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

graph_get_current_column_colorअगर यह एक खराब पॉइंटर का सामना करता है, तो आपके कार्य की तरह कार्य शायद पूरी तरह से कुछ भी करने में असमर्थ है, इसलिए मैं इसके कॉलर्स के लिए NULL की जाँच करना छोड़ दूंगा।


1

मैं कहूंगा कि यह निम्नलिखित पर निर्भर करता है:

  1. क्या CPU उपयोग महत्वपूर्ण है? NULL के लिए हर चेक में कुछ समय लगता है।
  2. क्या संकेत हैं कि सूचक NULL है? क्या यह सिर्फ पिछले फ़ंक्शन में उपयोग किया गया था। क्या पॉइंटर के मूल्य को बदला जा सकता था।
  3. क्या सिस्टम प्रीमेप्टिव है? क्या कोई कार्य बदल सकता है और मूल्य बदल सकता है? क्या कोई ISR आ सकता है और मूल्य बदल सकता है?
  4. कैसे कसकर युग्मित कोड है?
  5. क्या स्वचालित तंत्र के कुछ प्रकार हैं जो NULL पॉइंटर्स के लिए स्वचालित रूप से जांच करेंगे?

CPU यूटिलाइजेशन / ऑड्स पॉइंटर NULL है हर बार जब आप NULL की जांच करते हैं तो समय लगता है। इस कारण से मैं अपने चेक को सीमित करने की कोशिश करता हूं जहां पॉइंटर अपने मूल्य को बदल सकता था।

प्रीमेप्टिव सिस्टम यदि आपका कोड चल रहा है और कोई अन्य कार्य इसे बाधित कर सकता है और संभावित रूप से मूल्य बदल सकता है तो चेक अच्छा होगा।

कसकर युग्मित मॉड्यूल यदि सिस्टम कसकर युग्मित है, तो यह समझ में आएगा कि आपके पास अधिक जांचें हैं। मेरे कहने का मतलब यह है कि अगर डेटा संरचनाएं हैं जो कई मॉड्यूलों के बीच साझा की जाती हैं तो एक मॉड्यूल दूसरे मॉड्यूल के तहत कुछ बदल सकता है। इन स्थितियों में यह अधिक बार जांच करने के लिए समझ में आता है।

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

यदि यह उपलब्ध है तो परीक्षण करने के लिए एक सूचक के साथ एक कार्यक्रम बनाएं। सूचक को 0 पर सेट करें और फिर उसे पढ़ने / लिखने का प्रयास करें।


मुझे नहीं पता कि मैं एक स्वत: पूर्ण जाँच करने के रूप में segfault को वर्गीकृत करूँगा या नहीं। मैं मानता हूं कि CPU मेमोरी प्रोटेक्शन होने से मदद मिलती है ताकि एक प्रक्रिया बाकी सिस्टम को उतना नुकसान न पहुंचा सके लेकिन मैं इसे ऑटोमैटिक प्रोटेक्शन नहीं कहूंगा।
गैब्रियल दक्षिणी

1

मेरी राय में, इनपुट त्रुटियों (पूर्व / पोस्ट-स्थिति, अर्थात) को मान्य करना प्रोग्रामिंग त्रुटियों का पता लगाने के लिए एक अच्छी बात है, लेकिन केवल अगर यह एक तरह की ज़ोरदार और अप्रिय, शो-स्टॉप त्रुटियों का परिणाम है, जिसे अनदेखा नहीं किया जा सकता है। assertआमतौर पर इसका प्रभाव होता है।

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

एक उदाहरण के रूप में, मैंने कुछ सहयोगियों के साथ काम किया, जो मानते थे कि किसी को धार्मिक रूप से अशक्त बिंदुओं की उपस्थिति की जांच करनी चाहिए, इसलिए उन्होंने इस तरह के बहुत सारे कोड छिड़क दिए:

void vertex_move(Vertex* v)
{
     if (!v)
          return;
     ...
}

... और कभी-कभी ऐसा ही होता है बिना किसी त्रुटि कोड को वापस करने / सेट करने के भी। और यह एक कोडबेस में था जो कई दशकों पुराने कई थर्ड पार्टी प्लगइन्स के साथ था। यह कई कोडस से ग्रस्त एक कोडबेस भी था, और अक्सर बग जो मूल कारणों से पता लगाने में बहुत मुश्किल थे क्योंकि उनके पास समस्या के तत्काल स्रोत से हटाए गए साइटों में दुर्घटनाग्रस्त होने की प्रवृत्ति थी।

और यह अभ्यास एक कारण था। यह ऊपर की एक स्थापित पूर्व स्थिति का उल्लंघन हैmove_vertex फ़ंक्शन लिए एक अशक्त क्रिया को पारित करना है, फिर भी इस तरह के एक समारोह ने चुपचाप इसे स्वीकार कर लिया और प्रतिक्रिया में कुछ भी नहीं किया। तो क्या हुआ, यह था कि एक प्लगइन प्रोग्रामर की गलती हो सकती है, जो इसे उक्त फ़ंक्शन को पास करने का कारण बनता है, केवल इसका पता लगाने के लिए नहीं, केवल बाद में कई चीजें करने के लिए, और अंततः सिस्टम बाहर या दुर्घटना शुरू हो जाएगा।

लेकिन यहां वास्तविक मुद्दा इस समस्या का आसानी से पता लगाने में असमर्थता थी। इसलिए मैंने एक बार यह देखने की कोशिश की कि क्या होगा अगर मैंने एनालॉग कोड को एक से ऊपर कर दिया assert, जैसे:

void vertex_move(Vertex* v)
{
     assert(v && "Vertex should never be null!");
     ...
}

... और मेरे डर से, मैंने पाया कि आवेदन शुरू करने पर भी बाएं और दाएं विफल रहा है। मैंने पहले कुछ कॉल साइटों को तय करने के बाद, मैंने कुछ और चीजें कीं और फिर एक नाव पर अधिक जोर देने की असफलताएं मिलीं। मैं तब तक चलता रहा जब तक कि मैंने इतना कोड संशोधित नहीं कर लिया कि मैंने अपने परिवर्तनों को वापस करना शुरू कर दिया क्योंकि वे बहुत ज्यादा घुसपैठिया हो गए थे और भद्दे तरीके से उस अशक्त पॉइंटर चेक को रखने के बजाय, यह दस्तावेज करने के बजाय कि फ़ंक्शन एक अशक्त क्रिया को स्वीकार करने की अनुमति देता है।

लेकिन यह वह खतरा है, जो एक बुरी स्थिति है, जो पूर्व / बाद की स्थितियों के उल्लंघन को आसानी से पता लगाने में नाकाम रहने का है। फिर, आप वर्षों से, परीक्षण के रडार के नीचे उड़ान भरते हुए, ऐसे पूर्व / बाद की स्थितियों का उल्लंघन करते हुए चुपचाप कोड का एक नाव लोड कर सकते हैं। मेरी राय में इस तरह के एक शून्य सूचक एक नरम और अप्रिय मुखर विफलता के बाहर की जाँच वास्तव में दूर कर सकता है, अच्छे से कहीं अधिक नुकसान।

जब आप अशक्त बिंदुओं के लिए जाँच करनी चाहिए, तो आवश्यक प्रश्न के रूप में, मुझे विश्वास है कि अगर यह प्रोग्रामर त्रुटि का पता लगाने के लिए डिज़ाइन किया गया है, और इसे चुप और कठिन का पता लगाने के लिए नहीं बनाया गया है। यदि यह प्रोग्रामिंग त्रुटि नहीं है और प्रोग्रामर के नियंत्रण से परे कुछ है, जैसे मेमोरी फेल होना, तो यह अशक्त की जांच करने और त्रुटि से निपटने के लिए समझ में आता है। इसके अलावा कि यह एक डिजाइन प्रश्न है और आपके कार्यों को मान्य पूर्व / पोस्ट की शर्तों के आधार पर माना जाता है।


0

एक अभ्यास हमेशा अशक्त जांच करना है जब तक कि आपने पहले ही इसकी जाँच नहीं की है; इसलिए यदि इनपुट ए (ए) से बी () तक पारित किया जा रहा है, और ए () ने पहले से ही सूचक को मान्य किया है और आप निश्चित हैं कि बी (कहीं और नहीं बुलाया जाता है, तो बी () ए पर भरोसा कर सकते हैं) डेटा को साफ किया।


1
... 6 महीने के समय में जब तक कोई व्यक्ति आता है और कुछ और कोड जोड़ता है जो B () कहते हैं (संभवतः यह मानते हुए कि जिसने भी B लिखा है) निश्चित रूप से NULLs के लिए ठीक से जांचा गया है)। फिर तुम खराब हो, तुम नहीं हो? मूल नियम - यदि किसी फ़ंक्शन के लिए इनपुट के लिए एक अमान्य स्थिति मौजूद है, तो उसके लिए जांचें, क्योंकि इनपुट फ़ंक्शन के नियंत्रण से बाहर है।
मैक्सिमस मिनिमस

@ mh01 अगर आप सिर्फ रैंडम कोड (यानी अनुमान बना रहे हैं और डॉक्यूमेंट नहीं पढ़ रहे हैं) बाहर निकाल रहे हैं, तो मुझे नहीं लगता कि अतिरिक्त NULLचेक बहुत कुछ करने जा रहे हैं। इसके बारे में सोचो: अब के लिए B()जाँच करता है NULLऔर ... क्या करता है? वापसी -1? अगर कॉल करने वाले की जाँच नहीं होती हैNULL , तो आपको क्या भरोसा हो सकता है कि वे -1वैसे भी रिटर्न वैल्यू के मामले से निपटने जा रहे हैं ?
detly

1
यह कॉलर की जिम्मेदारी है। आप अपनी जिम्मेदारी से निपटते हैं, जिसमें आपके द्वारा दिए गए किसी भी मनमाने / अनजाने / संभावित-असत्यापित इनपुट पर भरोसा नहीं करना शामिल है। अन्यथा आप कॉप-आउट शहर में हैं। यदि कॉलर की जाँच नहीं होती है, तो कॉलर ने खराब कर दिया है; आपने चेक किया, आपका अपना गधा कवर किया गया है, आप बता सकते हैं कि जिसने भी फोन किया है कि आपने कम से कम चीजों को सही किया है।
मैक्सिमस मिनिमस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.