सी में, कुछ लोगों ने सूचक को मुक्त करने से पहले क्यों डाला?


167

मैं एक पुराने कोड आधार पर काम कर रहा हूं और बहुत ज्यादा मुफ्त का हर मंगलाचरण () अपने तर्क पर एक कास्ट का उपयोग करता है। उदाहरण के लिए,

free((float *)velocity);
free((float *)acceleration);
free((char *)label);

जहाँ प्रत्येक सूचक इसी (और मिलान) प्रकार का होता है। मुझे ऐसा करने का कोई मतलब नहीं है। यह बहुत पुराना कोड है, इसलिए यदि K & R चीज है तो मैं आश्चर्यचकित रह जाता हूं। यदि हां, तो मैं वास्तव में पुराने कंपाइलरों का समर्थन करना चाहता हूं जिनके लिए यह आवश्यक हो सकता है, इसलिए मैं उन्हें निकालना नहीं चाहता।

क्या इन जातियों का उपयोग करने का कोई तकनीकी कारण है? मैं भी उन्हें उपयोग करने के लिए एक व्यावहारिक कारण के ज्यादा नहीं देखते हैं। इसे मुक्त करने से ठीक पहले डेटा प्रकार की याद दिलाने की बात क्या है?

EDIT: यह प्रश्न अन्य प्रश्न का डुप्लिकेट नहीं है। अन्य प्रश्न इस प्रश्न का एक विशेष मामला है, जो मुझे लगता है कि अगर मतदाता सभी उत्तरों को पढ़ेंगे तो यह स्पष्ट है।

Colophon: मैं "कांस्ट उत्तर" चेकमार्क दे रहा हूं क्योंकि यह एक वास्तविक कारण है कि ऐसा करने की आवश्यकता क्यों हो सकती है; हालाँकि, इसके बारे में जवाब एक पूर्व-एएनएसआई सी प्रथा (कम से कम कुछ प्रोग्रामर के बीच) होने के कारण लगता है कि यह मेरे मामले में इस्तेमाल किया गया था। यहाँ बहुत से लोगों द्वारा बहुत सारे अच्छे अंक। आपके योगदानों के लिए धन्यवाद।


13
"इसे मुक्त करने से पहले डेटा प्रकार की याद दिलाने की क्या बात है?" शायद यह जानने के लिए कि कितनी स्मृति को मुक्त किया जाएगा?
m0skit0 12

12
@ कोड कंपाइलर डीक्लोकेशन नहीं करता है, ऑपरेटिंग सिस्टम करता है।
m0skit0 12

20
@ m0skit0 "शायद यह जानने के लिए कि कितनी स्मृति को मुक्त किया जाएगा?" फ्री में कितना है, यह जानने के लिए टाइप आवश्यक नहीं है। उस कारण के लिए कास्ट केवल खराब कोडिंग है।
user694733 12

9
पठनीयता के लिए @ m0skit0 कास्टिंग हमेशा खराब कोडिंग होती है, क्योंकि कास्टिंग में परिवर्तन होते हैं कि किस प्रकार व्याख्या की जाती है और यह अन्य त्रुटियों को छिपा सकता है। जब पठनीयता की आवश्यकता होती है, तो टिप्पणियाँ बेहतर होती हैं।
user694733

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

जवाबों:


171

यदि संकलक हैं तो संकलक चेतावनी को हल करने के लिए कास्टिंग की आवश्यकता हो सकती है const। यहां कोड का एक उदाहरण दिया गया है, जो मुफ्त के तर्क को डाले बिना चेतावनी देता है:

const float* velocity = malloc(2*sizeof(float));
free(velocity);

और कंपाइलर (जीसीसी 4.8.3) कहता है:

main.c: In function main’:
main.c:9:5: warning: passing argument 1 of free discards const qualifier from pointer target type [enabled by default]
     free(velocity);
     ^
In file included from main.c:2:0:
/usr/include/stdlib.h:482:13: note: expected void *’ but argument is of type const float *’
 extern void free (void *__ptr) __THROW;

यदि आप free((float*) velocity);संकलक का उपयोग करते हैं तो शिकायत करना बंद कर देता है।


2
@ m0skit0 यह नहीं समझाता है कि किसी को float*मुक्त करने से पहले क्यों डाला जाएगा । मैंने free((void *)velocity);gcc के साथ 4.8.3 की कोशिश की । बेशक यह एक प्राचीन संकलक के साथ काम नहीं करेगा
मानोस निकोलाइडिस

54
लेकिन आपको निरंतर मेमोरी को गतिशील रूप से आवंटित करने की आवश्यकता क्यों होगी? आप इसका इस्तेमाल कभी नहीं कर सकते!
Nils_M

33
@Nils_M यह एक बिंदु बनाने के लिए एक सरल उदाहरण है। मैंने एक फ़ंक्शन में वास्तविक कोड में क्या किया है, नॉन-कास्ट मेमोरी आवंटित की है, मान असाइन करें, एक कास्ट पॉइंटर को डाली और इसे वापस लौटाएं। अब, किसी व्यक्ति को मुक्त करने के लिए किसी स्थिर स्मृति को दर्शाने के लिए एक संकेतक है।
मानोस निकोलाइडिस

2
उदाहरण : “ये सबरूटीन नई मॉलोकेड मेमोरी में स्ट्रिंग लौटाते हैं, जो कि * stringValueP द्वारा इंगित किया जाता है, कि आपको अंततः मुक्त होना चाहिए। कभी-कभी, आप मुफ्त मेमोरी का उपयोग करने वाले ओएस फ़ंक्शन को अपने तर्क के रूप में गैर-स्थिरांक के लिए एक पॉइंटर लेने के लिए घोषित किया जाता है, इसलिए क्योंकि * stringValueP एक कास्ट के लिए एक पॉइंटर है। "
कार्स्टन एस

3
त्रुटिपूर्ण, यदि कोई फ़ंक्शन const char *pएक तर्क के रूप में लेता है और फिर उसे मुक्त करता है, तो मुफ्त कॉल करने pसे char*पहले कास्ट करने के लिए सही बात नहीं है । इसे const char *pपहली जगह लेने के रूप में घोषित नहीं करना है, क्योंकि यह संशोधित करता है *p और उसी के अनुसार घोषित किया जाना चाहिए। (और अगर यह पॉइंटर को पॉइंटर के बजाय कॉन्सटर में ले जाता है int *const p, तो आपको कास्ट करने की आवश्यकता नहीं है क्योंकि यह वास्तव में कानूनी है और इस तरह से कलाकारों के बिना ठीक काम करता है।)
रे

59

पूर्व-मानक सी में void*केवल और केवल नहीं थाchar* , इसलिए आपको पास किए गए सभी मापदंडों को डालना होगा। यदि आप प्राचीन C कोड में आते हैं, तो आप इस तरह की जातियाँ पा सकते हैं।

इसी तरह के सवाल संदर्भों के साथ

जब पहली सी मानक जारी किया गया था, malloc और मुक्त करने के लिए प्रोटोटाइप होने से बदल char*करने के लिए void*आज भी है।

और निश्चित रूप से मानक सी में, इस तरह की जातियां बहुत ही कम हैं और पठनीयता को नुकसान पहुंचाती हैं।


23
लेकिन आप इस तर्क को freeउसी प्रकार से क्यों लिखेंगे जो पहले से है?
jwodder

4
@chux पूर्व-मानक के साथ समस्या यह है कि: किसी भी चीज़ के लिए कोई दायित्व नहीं हैं। लोगों ने सिर्फ कैनन के लिए K & R पुस्तक पर ध्यान दिया क्योंकि वे केवल एक चीज थी। और जैसा कि हम K & R 2nd संस्करण में कई उदाहरणों से देख सकते हैं, K & R खुद इस बात को लेकर असमंजस में हैं कि freeमानक C में काम करने के लिए पैरामीटर की कास्ट कैसी है (आपको कास्ट करने की आवश्यकता नहीं है)। मैंने 1 संस्करण नहीं पढ़ा है इसलिए मैं नहीं बता सकता कि क्या वे 80 के दशक के पूर्व-मानक समय में भी भ्रमित थे।
लुंडिन

7
पूर्व-मानक C में नहीं था void*, लेकिन इसमें फ़ंक्शन प्रोटोटाइप भी नहीं थे, इसलिए freeK & R में भी अभी भी अनावश्यक तर्क वितर्क करना (सभी डेटा पॉइंटर प्रकारों को समान प्रतिनिधित्व का उपयोग करते हुए मान लिया गया था)।
इयान एबॉट

6
पहले से ही टिप्पणियों में वर्णित कई कारणों से, मुझे नहीं लगता कि यह उत्तर समझ में आता है।
आर .. गिटहब स्टॉप हेल्पिंग ICE

4
मैं यह नहीं देखता कि यह उत्तर वास्तव में किसी भी प्रासंगिक का जवाब कैसे देगा। मूल प्रश्न में अन्य प्रकारों को शामिल किया गया है, न केवल करने के लिए char *। पुराने संकलक के बिना इसका क्या अर्थ होगा void? ऐसी जातियां क्या हासिल करेंगी?
दोपहर

34

यहाँ एक उदाहरण दिया गया है जहाँ मुफ्त में कलाकारों के बिना असफल होंगे:

volatile int* p = (volatile int*)malloc(5 * sizeof(int));
free(p);        // fail: warning C4090: 'function' : different 'volatile' qualifiers
free((int*)p);  // success :)
free((void*)p); // success :)

C में आपको एक चेतावनी मिल सकती है (VS2012 में एक मिला)। C ++ में आपको एक त्रुटि मिलेगी।

दुर्लभ मामलों में एक तरफ, कास्टिंग सिर्फ कोड को ब्लॉट करता है ...

संपादित करें: मैंने विफलता को प्रदर्शित void*नहीं int*करने के लिए कास्ट किया । यह उसी तरह काम करेगा जैसा int*कि void*निहितार्थ में परिवर्तित किया जाएगा । जोड़ा गया int*कोड।


ध्यान दें कि प्रश्न में पोस्ट किए गए कोड में, कास्ट नहीं void *, बल्कि float *और हैं char *। वे जातियां सिर्फ बाहरी नहीं हैं, वे गलत हैं।
एंड्रयू हेनले

1
सवाल वास्तव में इसके विपरीत है।
m0skit0

1
मैं उत्तर नहीं समझता; किस अर्थ में free(p)असफल होगा ? क्या यह एक संकलक त्रुटि देगा?
कोडर

1
ये अच्छे अंक हैं। समान constरूप से क्वालिफायर पॉइंटर्स के साथ जाता है ।
लंडिन 12

2
volatileC अस्तित्व में है क्योंकि C को मानकीकृत नहीं किया गया था। इसे C99 में नहीं जोड़ा गया था ।
आर .. गिटहब स्टॉप हेल्पिंग ICE

30

पुराना कारण: 1. उपयोग करके free((sometype*) ptr), कोड स्पष्ट है कि सूचक को free()कॉल के भाग के रूप में माना जाना चाहिए । स्पष्ट कास्ट तब उपयोगी होता free()है जब उसे (डू-इट-खुद) से बदल दिया जाता है DIY_free()

#define free(ptr) DIY_free(ptr, sizeof (*ptr))

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

  1. स्मृति के मुद्दों को ट्रैक करने में बिताए गए कई घंटों को देखते हुए, टाइप फ्रीलाइड को कास्टिंग करने जैसी छोटी ट्रिक डीबगिंग को खोजने और कम करने में मदद करेगी।

आधुनिक: मानोस निकोलाइडिस @ और @egur द्वारा संबोधित के रूप में परहेज constऔर volatileचेतावनी । सोचा मैं 3 के प्रभाव ध्यान दें होगा क्वालिफायर : , , और ।constvolatilerestrict

[संपादित करें @ @char * restrict *rp2 प्रति टिप्पणी जोड़ा गया

void free_test(const char *cp, volatile char *vp, char * restrict rp, 
    char * restrict *rp2) {
  free(cp);  // warning
  free(vp);  // warning
  free(rp);  // OK
  free(rp2);  // warning
}

int main(void) {
  free_test(0,0,0,0);
  return 0;
}

3
restrictकेवल एक गैर-मुद्दा है क्योंकि यह कहाँ रखा गया है - यह ऑब्जेक्ट rpको इंगित नहीं करने वाले प्रकार को प्रभावित करता है । यदि आप के बजाय था char *restrict *rp, तो यह बात होगी।
आर .. गिटहब स्टॉप हेल्पिंग ICE

16

यहाँ एक और वैकल्पिक परिकल्पना है।

हमें बताया गया है कि कार्यक्रम को पूर्व C89 लिखा गया था, जिसका अर्थ है कि यह प्रोटोटाइप के साथ किसी प्रकार के बेमेल के आसपास काम नहीं कर सकता है free, क्योंकि न तो ऐसी कोई चीज थी और constन ही void *C89 से पहले, ऐसी कोई बात नहीं थी C89 से पहले एक फ़ंक्शन प्रोटोटाइपstdlib.hस्वयं समिति का आविष्कार था। यदि सिस्टम हेडर freeसभी को घोषित करने के लिए परेशान करते हैं, तो उन्होंने इसे इस तरह किया होगा:

extern free();  /* no `void` return type either! */

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

हालाँकि, इसका मतलब यह नहीं है कि freeअधिकांश K & R संकलकों पर तर्क देना आवश्यक था । एक समारोह की तरह

free_stuff(a, b, c)
    float *a;
    char *b;
    int *c;
{
    free(a);
    free(b);
    free(c);
}

सही ढंग से संकलित किया जाना चाहिए था। इसलिए मुझे लगता है कि हमें यहां जो मिला है वह एक असामान्य वातावरण के लिए एक छोटी गाड़ी संकलक के साथ सामना करने के लिए लिखा गया है: उदाहरण के लिए, एक वातावरण जहां sizeof(float *) > sizeof(int)और संकलक नहीं होगा बिंदुओं के लिए उपयुक्त कॉलिंग कन्वेंशन का उपयोग जब तक कि आप उन्हें बिंदु पर नहीं डालते। कॉल का।

मैं ऐसे किसी भी वातावरण के बारे में नहीं जानता, लेकिन इसका मतलब यह नहीं है कि वहाँ कोई नहीं था। सबसे संभावित उम्मीदवार जो दिमाग में आते हैं, वे 8-10 के लिए "छोटे सी" कंपाइलर हैं और 1980 के दशक की शुरुआत में 16-बिट माइक्रो। मुझे यह जानकर भी आश्चर्य नहीं होगा कि शुरुआती क्रेज़ में इस तरह की समस्याएं थीं।


1
पहली छमाही मैं पूरी तरह से सहमत हूं। और 2 आधा एक पेचीदा और प्रशंसनीय अनुमान है।
chux -

9

मुक्त पैरामीटर के रूप में केवल गैर-कास्ट पॉइंटर्स में लेता है। तो कॉन्स्ट पॉइंटर्स के मामले में, नॉन-कॉस्ट पॉइंटर के लिए स्पष्ट कास्टिंग की आवश्यकता होती है।

C में फ्री कॉन्स्ट पॉइंटर्स करने में असमर्थ

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.