विशेष रूप से, मॉलॉक के परिणाम के बारे में खतरनाक क्या है?


86

अब इससे पहले कि लोग इस डुप्लिकेट को चिह्नित करना शुरू करें, मैंने सभी निम्नलिखित को पढ़ा है, जिनमें से कोई भी उत्तर नहीं है जो मैं देख रहा हूं:

  1. सी अकसर किये गए सवाल: मॉलॉक के रिटर्न वैल्यू को लेकर क्या गलत है?
  2. SO: क्या मुझे स्पष्ट रूप से मॉलोक () रिटर्न वैल्यू कास्ट करना चाहिए?
  3. SO: C में अनावश्यक सूचक
  4. SO: क्या मैं मॉलॉक का परिणाम डाल सकता हूं?

दोनों C FAQ और उपरोक्त प्रश्नों के कई उत्तर एक रहस्यमय त्रुटि का हवाला देते हैं, जो कि mallocरिटर्न वैल्यू को छिपा सकती है; हालांकि, उनमें से कोई भी अभ्यास में इस तरह की त्रुटि का एक विशिष्ट उदाहरण नहीं देता है। अब ध्यान दें कि मैंने कहा त्रुटि , चेतावनी नहीं ।

अब निम्नलिखित कोड दिया गया है:

#include <string.h>
#include <stdio.h>
// #include <stdlib.h>

int main(int argc, char** argv) {

    char * p = /*(char*)*/malloc(10);
    strcpy(p, "hello");
    printf("%s\n", p);

    return 0;
}

उपरोक्त कोड को gcc 4.2 के साथ, कलाकारों के साथ और बिना संकलित करने से एक ही चेतावनी मिलती है, और प्रोग्राम ठीक से निष्पादित होता है और दोनों मामलों में समान परिणाम प्रदान करता है।

anon@anon:~/$ gcc -Wextra nostdlib_malloc.c -o nostdlib_malloc
nostdlib_malloc.c: In function ‘main’:
nostdlib_malloc.c:7: warning: incompatible implicit declaration of built-in function ‘malloc’
anon@anon:~/$ ./nostdlib_malloc 
hello

तो क्या कोई संकलन या रनटाइम त्रुटि का एक विशिष्ट कोड उदाहरण दे सकता है जो कास्टिंग mallocरिटर्न के मूल्य के कारण हो सकता है , या यह सिर्फ एक शहरी किंवदंती है?

संपादित करें मैं दो अच्छी तरह से लिखा इस मुद्दे के बारे में बहस का सामना करना पड़ा:

  1. कास्टिंग के पक्ष में: सीईआरटी सलाहकार: तुरंत आवंटित प्रकार के लिए एक मेमोरी आवंटन फ़ंक्शन कॉल का परिणाम एक संकेतक में डाल दिया
  2. कास्टिंग के खिलाफ (2012-02-14 के अनुसार 404 त्रुटि: 2010-01-27 से इंटरनेट आर्काइव वेकबैक मशीन कॉपी का उपयोग करें । {2016-03-18: "robots.txt के कारण पृष्ठ क्रॉल या प्रदर्शित नहीं किया जा सकता है।"}।

6
कास्टिंग voidपॉइंटर्स कोड को C ++ के रूप में संकलित करने की अनुमति देता है; कुछ लोग कहते हैं कि यह एक विशेषता है, मैं कहूंगा कि यह एक बग है;)
क्रिस्टोफ़

1
अपने लिंक के पहले टिप्पणियों को भी पढ़ें, क्योंकि यह बताता है कि आपको कास्टिंग के बजाय क्या करना चाहिए: Securecoding.cert.org/confluence/display/seccode/…
क्रिस्टोफ़

3
मैं कलाकारों को शामिल करने के लिए सीईआरटी की सलाह लूंगा। इसके अलावा, मैं कभी भी stdlib.h को शामिल करना नहीं भूलता। :)
अभिनव

1
यहाँ एक संकलित रनटाइम त्रुटि के कारण एसओ का उदाहरणmalloc दिया int*गया है: 64-बिट आर्च पर कास्टिंग करना ।
जॉन_वेस्ट

1
इस प्रश्न को टैग Cनहीं किया गया है C++(वे दो अलग-अलग भाषाएं हैं) इसलिए किसी भी चर्चा (जैसा कि कुछ उत्तरों में है) इस प्रश्न के लिए प्रासंगिक नहीं है।
user3629249

जवाबों:


66

आपको एक संकलक त्रुटि नहीं मिलेगी , लेकिन एक संकलक चेतावनी । जैसा कि आप सूत्रों का हवाला देते हैं (विशेष रूप से पहले वाला ), आप बिना शामिल किए कलाकारों का उपयोग करते समय अप्रत्याशित रनटाइम त्रुटि प्राप्त कर सकते हैं ।stdlib.h

तो अपनी तरफ से त्रुटि डाली नहीं है, लेकिन शामिल करने के लिए भूल रहा है stdlib.h। संकलनकर्ता कि मान सकते हैं mallocएक समारोह लौटा रहा है int, इसलिए परिवर्तित void*सूचक वास्तव में द्वारा वापस mallocकरने के लिए intऔर फिर अपने सूचक प्रकार के स्पष्ट कलाकारों की वजह से। कुछ प्लेटफार्मों पर, intऔर पॉइंटर्स अलग-अलग संख्या में बाइट्स ले सकते हैं, इसलिए प्रकार रूपांतरण से डेटा भ्रष्टाचार हो सकता है।

सौभाग्य से, आधुनिक संकलक चेतावनी देते हैं जो आपकी वास्तविक त्रुटि को इंगित करते हैं। gccआपके द्वारा प्रदत्त आउटपुट देखें : यह आपको चेतावनी देता है कि अंतर्निहित घोषणा ( int malloc(int)) अंतर्निहित में असंगत है malloc। तो बिना जाने भी gccलगता है ।mallocstdlib.h

इस त्रुटि को रोकने के लिए कलाकारों को छोड़ना ज्यादातर लेखन के समान तर्क है

if (0 == my_var)

के बजाय

if (my_var == 0)

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

इसके द्वारा लौटाए गए मान की ढलाई के लिए भी यही सही है malloc: मैं प्रोग्रामिंग में स्पष्ट रहना पसंद करता हूं और आमतौर पर सभी कार्यों के लिए हेडर फ़ाइलों को शामिल करने के लिए डबल-चेक करता हूं।


2
ऐसा लगता है कि चूंकि संकलक असंगत निहित घोषणा के बारे में चेतावनी देता है, तो यह एक गैर-मुद्दा है जब तक आप अपने संकलक की चेतावनी पर ध्यान देते हैं।
रॉबर्ट एस। बार्न्स

4
@ रॉबर्ट: हाँ, संकलक के बारे में कुछ धारणाएँ दी हैं। जब लोग सी को सामान्य रूप से लिखने के लिए सर्वोत्तम सलाह दे रहे हैं , तो वे यह नहीं मान सकते कि सलाह प्राप्त करने वाला व्यक्ति gcc के हालिया संस्करण का उपयोग कर रहा है।
स्टीव जेसप

4
ओह, और दूसरे प्रश्न का उत्तर यह है कि कॉल करने वाले में रिटर्न वैल्यू लेने के लिए कोड होता है (जो यह सोचता है कि यह एक इंट है), और इसे T * में बदल दें। कैली केवल रिटर्न मान (शून्य * के रूप में) और रिटर्न लिखता है। इसलिए कॉलिंग कन्वेंशन के आधार पर: इंट रिटर्न और शून्य * रिटर्न "एक ही जगह" (रजिस्टर या स्टैक स्लॉट) में हो सकता है या नहीं भी हो सकता है; int और void * समान आकार का हो सकता है या नहीं भी हो सकता है; दोनों के बीच परिवर्तित करना कोई विकल्प नहीं हो सकता है। तो यह "बस काम" हो सकता है, या मूल्य दूषित हो सकता है (कुछ बिट खो गए, शायद), या कॉलर पूरी तरह से गलत मूल्य उठा सकता है।
स्टीव जेसप

1
@ RobertS.Barnes पार्टी के लिए देर से, लेकिन: वापसी मूल्य आम तौर पर फ़ंक्शन हस्ताक्षर का हिस्सा नहीं है, यहां तक ​​कि सी ++ में भी नहीं। लिंकर सिर्फ एक प्रतीक के लिए एक कूद उत्पन्न करता है, बस।
पीटर - मोनिका

3
जब आप stdlib.h को शामिल किए बिना कलाकारों का उपयोग कर रहे हैं, तो आप एक अप्रत्याशित रनटाइम त्रुटि प्राप्त कर सकते हैं । यह सच है, लेकिन इसमें शामिल नहीं stdlib.hहै, पहले से ही अपने आप में एक त्रुटि है, भले ही आपको केवल "इनसाइटिस घोषणा" चेतावनी मिले।
Jabberwocky

45

परिणाम कास्ट करने के खिलाफ अच्छे उच्च-स्तरीय तर्कों में से mallocएक को अक्सर छोड़ दिया जाता है, भले ही, मेरी राय में, यह प्रसिद्ध-निचले स्तर के मुद्दों से अधिक महत्वपूर्ण है (जैसे कि घोषणा गायब होने पर सूचक को रौंदना)।

एक अच्छा प्रोग्रामिंग अभ्यास कोड लिखना है, जो यथासंभव स्वतंत्र है। इसका अर्थ है, विशेष रूप से, उस प्रकार के नामों को कोड में कम से कम या सबसे अच्छा उल्लेख नहीं किया जाना चाहिए। यह जातियों पर लागू होता है (अनावश्यक जाति से बचें), प्रकार के तर्क के रूप में sizeof(प्रकार के नामों का उपयोग करने से बचें sizeof) और, आम तौर पर, अन्य सभी प्रकार के नाम।

प्रकार के नाम घोषणाओं में हैं। जितना संभव हो, टाइप नाम केवल घोषणाओं तक ही सीमित होना चाहिए और केवल घोषणाओं तक ही सीमित होना चाहिए।

इस दृष्टि से, यह बिट कोड खराब है

int *p;
...
p = (int*) malloc(n * sizeof(int));

और यह बहुत बेहतर है

int *p;
...
p = malloc(n * sizeof *p);

केवल इसलिए नहीं क्योंकि यह "का परिणाम नहीं देता है malloc", बल्कि इसलिए कि यह टाइप-इंडिपेंडेंट (या टाइप-एगोनिसेटिक, यदि आप पसंद करते हैं) है, क्योंकि यह अपने आप को जो भी प्रकार के pसाथ घोषित किया गया है, से किसी भी हस्तक्षेप की आवश्यकता के बिना समायोजित करता है । उपभोक्ता।


Fwiw, मुझे लगता है कि यह कमोबेश यही कारण है: stackoverflow.com/questions/953112/… लेकिन DIY के बजाय टाइप-आज़ादी पर ध्यान केंद्रित किया। बेशक दूसरा (या इसके विपरीत) से पहला अनुसरण है, इसलिए कम से कम इसका उल्लेख कभी-कभी किया जाता है । :)
खोलना

5
@ आप सबसे अधिक संभावना का मतलब है DIY के
kratenko

18

गैर-प्रोटोटाइप किए गए कार्यों को वापस करने के लिए माना जाता है int

तो आप intएक पॉइंटर को कास्टिंग कर रहे हैं । यदि intआपके प्लेटफॉर्म पर पॉइंटर्स s से अधिक चौड़े हैं , तो यह अत्यधिक जोखिम भरा व्यवहार है।

इसके अलावा, ज़ाहिर है, कि कुछ लोगों को चेतावनी पर विचार करने के लिए किया त्रुटियों, यानी कोड उनके बिना संकलन चाहिए।

व्यक्तिगत रूप से, मुझे लगता है कि इस तथ्य को कि आपको void *किसी अन्य पॉइंटर प्रकार में डालने की आवश्यकता नहीं है, सी में एक विशेषता है, और उस कोड पर विचार करें जो टूटना नहीं है।


14
मेरी यह धारणा है कि संकलक भाषा के बारे में मुझसे ज्यादा जानता है, इसलिए यदि यह मुझे किसी चीज के बारे में चेतावनी देता है, तो मैं ध्यान देता हूं।
ग्योर्गी एंड्रेसेक

3
कई परियोजनाओं में, सी कोड को C ++ के रूप में संकलित किया जाता है, जहां आपको कास्ट करने की आवश्यकता होती है void*
लालाटो

नाइट: " डिफ़ॉल्ट रूप से , गैर-प्रोटोटाइप किए गए कार्यों को वापस करने के लिए माना जाता है int।" - क्या आपका मतलब है कि गैर-प्रोटोटाइप किए गए कार्यों के रिटर्न प्रकार को बदलना संभव है?
दोपहर

1
@ सलाम - यह है, लेकिन यह नहीं होना चाहिए C C है, C ++ नहीं है, और C संकलक के साथ संकलित किया जाना चाहिए, C ++ संकलक नहीं। कोई बहाना नहीं है: जीसीसी (सर्वश्रेष्ठ सी कंपाइलरों में से एक) लगभग हर प्लेटफ़ॉर्म पर कल्पनाशील है (और अत्यधिक अनुकूलित कोड भी बनाता है)। संभवतः आपको C ++ संकलक के साथ C को संकलित करने के लिए क्या कारण हो सकते हैं, आलस्य और ढीले मानकों के अलावा अन्य?
क्रिस लुत्ज़

3
कोड का उदाहरण जिसे आप C और C ++ दोनों के रूप में संकलित करना चाहते हैं #ifdef __cplusplus \nextern "C" { \n#endif static inline uint16_t swb(uint16_t a) {return ((a << 8) | ((a >> 8) & 0xFF); } \n#ifdef __cplusplus\n } \n#endif:। अब, आप मैलाक को एक स्थिर इनलाइन फंक्शन में क्यों बुलाना चाहते हैं, मैं वास्तव में नहीं जानता, लेकिन दोनों में काम करने वाले हेडर शायद ही अनसुने हैं।
16:17 पर स्टीव जेसप

11

यदि आप 64-बिट मोड में संकलन करते समय ऐसा करते हैं, तो आपके लौटे हुए पॉइंटर को 32-बिट्स में काट दिया जाएगा।

संपादित करें: बहुत संक्षिप्त होने के लिए क्षमा करें। चर्चा उद्देश्यों के लिए एक उदाहरण कोड टुकड़ा है।

मुख्य()
{
   char * c = (char *) malloc (2);
   प्रिंटफ ("% p", c);
}

मान लीजिए कि लौटे हीप पॉइंटर 0xAB00000000 कहते हैं, इंटेक में प्रतिनिधित्व करने योग्य से कुछ बड़ा है।

यदि मॉलोक एक पॉइंटर को वापस करने के लिए प्रोटोटाइप नहीं किया गया है, तो शुरू किया गया इंट वैल्यू शुरू में सभी महत्वपूर्ण बिट्स के साथ कुछ रजिस्टर में होगा। अब कंपाइलर कहता है, "ठीक है, मैं कैसे कन्वर्ट करता हूं और एक पॉइंटर को इंट करता हूं"। यह या तो एक संकेत विस्तार या कम क्रम 32-बिट्स का शून्य विस्तार होने जा रहा है जिसे प्रोटोटाइप को छोड़ कर मॉलॉक "रिटर्न" बताया गया है। चूंकि int पर हस्ताक्षर किए गए हैं, मुझे लगता है कि रूपांतरण साइन एक्सटेंशन होगा, जो इस मामले में मूल्य को शून्य में बदल देगा। 0xABF0000000 के रिटर्न वैल्यू के साथ आपको एक नॉन-जीरो पॉइंटर मिलेगा जो आपके द्वारा इसे टालने की कोशिश करने पर कुछ मज़ेदार भी होगा।


1
क्या आप विस्तार से बता सकते हैं कि यह कैसे होगा?
राबर्ट एस। बार्न्स

5
मुझे लगता है कि Peeter Joot यह अनुमान लगा रहा था कि "डिफ़ॉल्ट रूप से, गैर-प्रोटोटाइप किए गए कार्यों को वापस लौटने के लिए मान लिया गया है" w / o जिनमें stdlib.h शामिल है, और sizeof (int) 32 बिट्स हैं जबकि sizeof (ptr) 64 है
टेस्ट

4

एक पुन: प्रयोज्य सॉफ्टवेयर नियम:

एक इनलाइन फ़ंक्शन लिखने के मामले में जिसमें सी ++ कोड के लिए पुन: प्रयोज्य बनाने के लिए मॉलोक () का उपयोग किया जाता है, कृपया एक स्पष्ट प्रकार की कास्टिंग (जैसे (चार *)) करें; अन्यथा कंपाइलर शिकायत करेगा।


उम्मीद है कि (हाल ही में) gcc में लिंक-टाइम ऑप्टिमाइजेशन को शामिल करने के साथ (देखें gcc.gnu.org/ml/gcc/2009-10/msg00060.html ), हेडर फाइलों में इनलाइन-फंक्शन की घोषणा करना अब जरूरी नहीं होगा
क्रिस्टोफ

आपको बुरे विचार आए। क्या आप जानते हैं कि विभिन्न संकलक / संस्करण / आर्किटेक्चर के बीच पोर्टेबल और क्रॉस-प्लेटफॉर्म क्या है? ठीक है, तुम नहीं कर सकते फिर पुन: प्रयोज्य का क्या अर्थ है?
टेस्ट

2
C ++ लिखते समय, malloc / free सही पद्धति नहीं है। बल्कि नए / हटाएं का उपयोग करें। IE को C ++ कोड में Malloc / मुफ्त में कोई / नाडा / शून्य कॉल नहीं होना चाहिए
उपयोगकर्ता 3636249

3
@ user3629249: जब एक समारोह जो भीतर से प्रयोग करने योग्य होने की जरूरत है लेखन या तो , सी कोड या सी ++ कोड का उपयोग कर malloc/ freeके लिए दोनों का उपयोग करने की कोशिश कर की तुलना में बेहतर करने के लिए उपयुक्त है mallocसी में और newC ++, खासकर अगर डेटा संरचनाओं सी और सी के बीच साझा कर रहे हैं ++ कोड और एक संभावना है कि एक वस्तु सी कोड में बनाई जा सकती है और सी ++ कोड या इसके विपरीत में जारी की जा सकती है।
सुपरकट

3

C में एक शून्य पॉइंटर को एक स्पष्ट कास्ट के बिना किसी भी पॉइंटर को सौंपा जा सकता है। कंपाइलर चेतावनी देगा, लेकिन यह C ++ में टाइप कास्टिंग malloc()से संबंधित टाइप के लिए पुन: प्रयोज्य हो सकता है । बाहर टाइप कास्टिंग के साथ भी इसका उपयोग C में किया जा सकता है , क्योंकि C कोई सख्त प्रकार की जाँच नहीं है । लेकिन C ++ कड़ाई से जाँच कर रहा है, इसलिए malloc()C ++ में कास्ट टाइप करना आवश्यक है ।


यदि आप C ++ में मॉलोक का उपयोग करते हैं तो आपके पास बेहतर शापित कारण है! ; पी
एंटी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.