दिलचस्प पोस्ट
AngularJs: पुनः लोड करें पृष्ठ क्यों जावा बहुरूपता मेरे उदाहरण में काम नहीं करते दूरदराज के रिपॉजिटरी पर नहीं रह जाने वाले स्थानीय टैग निकालें प्रक्रिया संभालती कैसे गणना करना है? एक स्ट्रिंग में वर्ण घटनाओं की गणना करने का आसान तरीका जीडीबी के साथ प्रोग्राम के मुख्य डंप फ़ाइल का विश्लेषण कैसे करें? स्प्रिंग 4.2.3 और तेज xml जैक्सन 2.7.0 असंगत हैं CSS3 का उपयोग कर एक मंडल के सेगमेंट जावा निष्पादक सेवा कार्यों से अपवादों को संभालना Codeigniter में अपलोड – आप अपलोड करने का प्रयास कर रहे फ़ाइल प्रकार की अनुमति नहीं है रंगों में हेक्स पारदर्शिता मानक पुस्तकालय qsort को स्थिर करना? जावास्क्रिप्ट में अनिर्धारित या शून्य चर की जांच कैसे करें? मैं ऑडियो डीबी स्तर की गणना कैसे कर सकता हूं? कैसे jQuery में रिक्त वस्तुओं की जांच करने के लिए

फ़ंक्शन पॉइंटर्स और डेटा पॉइंटर्स सी / सी ++ में असंगत क्यों हैं?

मैंने पढ़ा है कि फ़ंक्शन पॉइंटर को डेटा पॉइंटर में परिवर्तित करना और इसके विपरीत, अधिकांश प्लेटफ़ॉर्म पर काम करता है लेकिन काम करने की गारंटी नहीं है। यह एक केस क्यों है? दोनों को बस मुख्य मेमोरी में बस नहीं होना चाहिए और इसलिए संगत होना चाहिए?

वेब के समाधान से एकत्रित समाधान "फ़ंक्शन पॉइंटर्स और डेटा पॉइंटर्स सी / सी ++ में असंगत क्यों हैं?"

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

कुछ कंप्यूटरों में (होते हैं) कोड और डेटा के लिए अलग पता स्थान। ऐसे हार्डवेयर पर यह काम नहीं करता है

भाषा को न केवल वर्तमान डेस्कटॉप अनुप्रयोगों के लिए डिज़ाइन किया गया है, लेकिन हार्डवेयर के बड़े सेट पर इसे लागू करने की अनुमति देने के लिए।


ऐसा लगता है जैसे सी भाषा कमेटी ने कार्य करने के लिए एक सूचक होने के लिए void* का इरादा नहीं किया, वे ऑब्जेक्ट के लिए सामान्य पॉइंटर चाहते थे

सीएएम का तर्क कहता है:

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

void* ("पॉइन्टर टू void ") का प्रयोग सामान्य ऑब्जेक्ट पॉइंटर प्रकार के रूप में C89 समिति का एक आविष्कार है। फ़ंक्शन प्रोटोटाइप तर्कों को निर्दिष्ट करने की इच्छा से इस प्रकार का दत्तक ग्रहण किया गया था कि या तो चुपचाप मनमानी संकेतों को strcmp ( strcmp रूप में) या शिकायत करते हैं कि तर्क प्रकार बिल्कुल मिलान नहीं होता है (जैसे कि strcmp )। कार्यों के लिए पॉइंटर्स के बारे में कुछ भी नहीं कहा जाता है, जो ऑब्जेक्ट पॉइंटर और / या इंटिजर्स के साथ असामान्य हो सकता है।

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

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

उदाहरण के लिए कॉम्पैक्ट मॉडल (छोटा कोड, बड़ा डेटा):

 sizeof(void *) > sizeof(void(*)()) 

और इसके विपरीत मध्यम मॉडल (बड़े कोड, छोटे डेटा) में:

 sizeof(void *) < sizeof(void(*)()) 

इस मामले में आपके पास कोड और तारीख के लिए अलग भंडार नहीं था, लेकिन फिर भी दो बिंदुओं (गैर मानक __near और __far modifiers का उपयोग करने की कमी) के बीच कन्वर्ट नहीं किया जा सका।

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

शून्य के संकेतकों को किसी भी प्रकार के डेटा के लिए एक सूचक को समायोजित करने में सक्षम होना चाहिए – लेकिन जरूरी नहीं कि फ़ंक्शन के लिए एक संकेतक। कुछ प्रणालियों में पॉइंटर्स के लिए डेटा को पॉइंटर्स की तुलना में कार्य करने के लिए अलग-अलग आवश्यकताओं की आवश्यकता होती है (उदाहरण के लिए, डीएसपी, डेटा बनाम कोड के लिए अलग-अलग एड्रेसिंग के साथ, एमएस-डॉस पर मध्यम मॉडल कोड के लिए 32-बिट पॉइंटर्स का प्रयोग किया जाता है, लेकिन डेटा के लिए केवल 16-बिट पॉइंटर्स) ।

पहले से ही यहां क्या कहा गया है इसके अतिरिक्त, POSIX dlsym() को देखना दिलचस्प है:

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

  fptr = (int (*)(int))dlsym(handle, "my_function"); 

यहां बताया गया समस्या के कारण, भविष्य के संस्करण या तो कार्य पॉइंटर्स लौटने के लिए एक नया फ़ंक्शन जोड़ सकते हैं या वर्तमान इंटरफ़ेस को दो नए फ़ंक्शन के पक्ष में पदावनत किया जा सकता है: जो कि डेटा पॉइंटर्स देता है और दूसरा जो कि फ़ंक्शन पॉइंटर्स देता है

लक्ष्य वास्तुकला पर निर्भर करता है, कोड और डेटा को मूल रूप से असंगत, स्मृति के भौतिक रूप से अलग क्षेत्रों में संग्रहित किया जा सकता है।

सी ++ 11 में dlsym() संबंध में सी / सी ++ और dlsym() बीच लंबे समय तक dlsym() का dlsym() । किसी एक reinterpret_cast सूचक को / से फ़ंक्शन पॉइंटर कन्वर्ट करने के लिए reinterpret_cast का उपयोग कर सकते हैं, जब तक कार्यान्वयन इस सुविधा का समर्थन करता है।

मानक से, 5.2.10 पैरा 8, "फ़ंक्शन पॉइंटर को ऑब्जेक्ट पॉइंटर प्रकार या इसके विपरीत में परिवर्तित करना सशर्त रूप से समर्थित है।" 1.3.5 "सशर्त रूप से समर्थित" को "प्रोग्राम निर्माण के रूप में परिभाषित करता है कि समर्थन के लिए कार्यान्वयन की आवश्यकता नहीं है"।

अनिवार्य रूप से जरूरी नहीं है कि इसका अर्थ नहीं है, इसका मतलब यह हो सकता है कि कंपाइलर लागूकर्ता को यह करने के लिए अधिक स्वतंत्रता है कि वे कैसे चाहते हैं।

उदाहरण के लिए यह कुछ आर्किटेक्चर पर संभव नहीं हो सकता है – अपरिभाषित होने के कारण उन्हें एक 'सी' लायब्रेरी के अनुरूप बनाने की अनुमति मिल सकती है, भले ही आप ऐसा नहीं कर सकें।

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

मेरा मानना ​​है कि वे अलग-अलग प्रकार के हो सकते हैं क्योंकि मानक संभव कार्यान्वयन को सीमित नहीं करना चाहता है जो अंतरिक्ष को बचाने की आवश्यकता नहीं है या जब आकार में सीपीयू को इसका इस्तेमाल करने के लिए अतिरिक्त बकवास करना पड़ सकता है …

एक और समाधान:

मान लें कि पॉसिक्स की गारंटी देता है कि कार्य और डेटा पॉइंटर्स समान आकार और प्रतिनिधित्व करते हैं (मुझे इसके लिए पाठ नहीं मिल सकता है, लेकिन उदाहरण के लिए ओपी ने सुझाव दिया है कि वे कम से कम इस आवश्यकता को पूरा करने का सुझाव देते हैं), निम्नलिखित कार्य करना चाहिए:

 double (*cosine)(double); void *tmp; handle = dlopen("libm.so", RTLD_LAZY); tmp = dlsym(handle, "cos"); memcpy(&cosine, &tmp, sizeof cosine); 

यह char [] प्रस्तुतीकरण के माध्यम से जाकर अलियासिंग नियमों का उल्लंघन करने से बचा जाता है, जिसे उपनाम सभी प्रकार की अनुमति है।

फिर भी एक और दृष्टिकोण:

 union { double (*fptr)(double); void *dptr; } u; u.dptr = dlsym(handle, "cos"); cosine = u.fptr; 

लेकिन अगर आप बिल्कुल 100% सही सी चाहते हैं तो मैं memcpy दृष्टिकोण memcpy

केवल सचमुच पोर्टेबल समाधान फ़ंक्शन के लिए dlsym का उपयोग नहीं करना है, और इसके बजाय dlsym का उपयोग करने के लिए सूचक पॉइंट को डेटा में प्राप्त करता है जिसमें फ़ंक्शन पॉइंटर्स होते हैं उदाहरण के लिए, आपकी लाइब्रेरी में:

 struct module foo_module = { .create = create_func, .destroy = destroy_func, .write = write_func, /* ... */ }; 

और फिर अपने आवेदन में:

 struct module *foo = dlsym(handle, "foo_module"); foo->create(/*...*/); /* ... */ 

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

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

हालांकि, यह कल्पनीय है कि फ़ंक्शन पॉइंटर्स को एक अलग प्रतिनिधित्व की आवश्यकता हो सकती है, शायद वे अन्य पॉइंटर्स से बड़ा हो। यदि शून्य * फ़ंक्शन पॉइंटर्स को पकड़ सकता है, तो इसका मतलब होगा कि शून्य * का प्रतिनिधित्व बड़ा आकार होगा। और सभी शून्य के लिए / से डेटा पॉइंटर्स को छोड़कर इस अतिरिक्त प्रतिलिपि को पूरा करना होगा।

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

इसका एक आधुनिक उदाहरण जहां फ़ंक्शन पॉइंटर्स डेटा पॉइंटर्स से आकार में भिन्न हो सकते हैं: C ++ क्लास सदस्य फ़ंक्शन पॉइंटर्स

सीधे https://blogs.msdn.microsoft.com/oldnewthing/20040209-00/?p=40713/ से उद्धृत

 class Base1 { int b1; void Base1Method(); }; class Base2 { int b2; void Base2Method(); }; class Derived : public Base1, Base2 { int d; void DerivedMethod(); }; 

अब दो संभावित this पॉइंटर्स हैं

Base1 सदस्य फ़ंक्शन के एक सूचक को Derived किसी सदस्य फ़ंक्शन के सूचक के रूप में इस्तेमाल किया जा सकता है, क्योंकि वे दोनों this सूचक का उपयोग करते हैं। लेकिन Base2 सदस्य फ़ंक्शन के लिए एक सूचक को इस्तेमाल नहीं किया जा Base2 जैसे कि Derived किसी सदस्य फ़ंक्शन के सूचक को है, क्योंकि this सूचक को समायोजित करने की आवश्यकता है।

इस को सुलझाने के कई तरीके हैं यहां देखें कि विजुअल स्टूडियो कंपाइलर इसे कैसे प्रबंधित करता है:

गुणा-उत्तराधिकृत वर्ग के सदस्य फ़ंक्शन के लिए एक सूचक वास्तव में एक संरचना है।

 [Address of function] [Adjustor] 

एकाधिक विरासत का उपयोग करने वाले किसी वर्ग के सूचक-से-सदस्य-फ़ंक्शन का आकार एक सूचक का आकार और size_t आकार का आकार है।

tl; dr: एकाधिक विरासत का उपयोग करते समय, सदस्य फ़ंक्शन पर एक सूचक (संकलक, संस्करण, वास्तुकला, आदि के आधार पर) वास्तव में संग्रहीत किया जाता है

 struct { void * func; size_t offset; } 

जो स्पष्ट रूप से एक void * से बड़ा है

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