2012-11-20 6 views
6

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

#include <iostream> 

struct testingPointers 
{ 
    int i; 
    float f; 
    double d; 
} test; 

int main() 
{ 
    std::cout << &test << '\n' << &(test.i) << '\n' << 
      &(test.f) << '\n' << &(test.d); 
} 

और उत्पादन होता है:

0x681110 
0x681110 
0x681114 
0x681118 

(स्पष्ट रूप से सटीक मान अलग रन के लिए अलग-अलग हैं लेकिन वे हमेशा के सापेक्ष एक ही स्थिति है कोड का एक छीन नीचे संस्करण इस प्रकार है एक दूसरे)।

मैं उलझन में हूं क्योंकि पहले पॉइंटर का मूल्य - test की मेमोरी लोकेशन - दूसरे की तरह ही है (test का पहला फ़ील्ड)। क्या इसका मतलब यह है कि वस्तुओं के पास कोई वास्तविक अद्वितीय स्मृति पता नहीं है, और यह कि एक संरचना या वर्ग के लिए सूचक केवल अपने पहले क्षेत्र को इंगित करता है? यदि हां, तो कैसे करना

a.b 
a->b 
a.b() 

मेकअप भावना की तरह बयान करता है, तो a वास्तव में सिर्फ अपनी पहली क्षेत्र है, और इसलिए किसी भी फ़ील्ड या विधियां नहीं हैं?

+2

नहीं, वे विभिन्न प्रकार के पॉइंटर्स हैं। लेकिन पहला क्षेत्र वस्तु की शुरुआत में स्थित है। तो यह एक ही प्रारंभिक पता है। (जब तक शुरुआत में एक vtable सूचक या कुछ नहीं है।) –

+8

यदि मेरे सिर के शीर्ष पर एक पॉइंटर भी मेरे सिर के शीर्ष पर एक सूचक है तो इसका मतलब है कि मैं अस्तित्व में नहीं हूं क्योंकि मैं वास्तव में सिर्फ एक सिर हूं? –

+0

@MooingDuck डरावना। –

उत्तर

5

एक वर्ग या संरचना सिर्फ उन क्षेत्रों के संग्रह का वर्णन करती है जिन्हें स्मृति में एक साथ रखा जाना चाहिए, और उनके बीच कुछ अर्थपूर्ण संबंध हैं और उन पर चलने वाले कुछ संचालन हैं। सरल मामले में, सदस्यों के मुकाबले मेमोरी में क्लास टाइप ऑब्जेक्ट की सामग्री के लिए और कुछ भी नहीं है (और कुछ पैडिंग)। जब आपके पास testingPointers ऑब्जेक्ट मेमोरी है, तो यह वास्तव में केवल int है, float और double है। कक्षा की अवधारणा का उपयोग केवल सही निष्पादन योग्य कोड उत्पन्न करने के लिए किया जाता था - यह रन टाइम पर मौजूद नहीं है (कम से कम इस उद्देश्य के लिए नहीं)।

के बारे में वस्तुओं स्मृति पतों साझा कर सकते हैं कि क्या मानक से महत्वपूर्ण हिस्सा §1.8/6:

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

हम इस से अनुमान लगा सकते हैं कि क्योंकि सदस्य test.itest की एक subobject है, वे अच्छी तरह से एक ही पते हो सकता है।

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

एक स्मृति स्थान या तो अदिश प्रकार का ऑब्जेक्ट या आसन्न बिट क्षेत्रों सब होने गैर शून्य चौड़ाई का एक अधिक से अधिक अनुक्रम है। [नोट: भाषा की विभिन्न विशेषताओं, जैसे कि संदर्भ और वर्चुअल फ़ंक्शन, में अतिरिक्त मेमोरी स्थान शामिल हो सकते हैं जो प्रोग्राम के लिए उपलब्ध नहीं हैं लेकिन कार्यान्वयन द्वारा प्रबंधित किए जाते हैं।- अंत टिप्पणी]

1

स्मृति में एक struct एक साथ बांधा अपने खेतों से ज्यादा कुछ नहीं के होते हैं। संरेखण आवश्यकताओं के आधार पर संरचना और/या फ़ील्ड के बीच पैडिंग हो सकती है, लेकिन आमतौर पर पहले फ़ील्ड से पहले कोई अतिरिक्त "सामान" नहीं होता है। तो पहले क्षेत्र और संरचना के पास एक ही पता है।

याद रखें कि सी में, प्रकार केवल संकलन समय पर मौजूद हैं।

+0

मैंने कभी भी एक कंपाइलर के बारे में नहीं सुना है जो पहले सदस्य से पहले पैडिंग रखता है, हालांकि मुझे यकीन नहीं है कि इसे सी में अनुमति है। मुझे लगता है कि यह cis+ में _is_ की अनुमति है (हालांकि अभी भी कभी नहीं देखा गया है)। –

+0

@MooingDuck मानक के अनुसार नहीं (9.2-20)। इस पोस्ट के चारों ओर तैरते हुए मेरा जवाब देखें। यह शुरुआत में * नहीं * की अनुमति है। – WhozCraig

6

किसी ऑब्जेक्ट का पता हमेशा उस ऑब्जेक्ट के पहले गैर-स्थैतिक सदस्य का पता होगा। मानक (सी ++ 11-9.2-20) से हवाला देते हुए:

एक मानक लेआउट struct वस्तु के लिए एक सूचक, उपयुक्त रूप से एक reinterpret_cast का उपयोग कर परिवर्तित, अपनी प्रारंभिक सदस्य को इंगित करता है (या एक है कि सदस्य है अगर बिट-फील्ड, फिर उस यूनिट में जिसमें यह रहता है) और इसके विपरीत। [नोट: इसलिए मानक-लेआउट स्ट्रक्चर ऑब्जेक्ट के भीतर अज्ञात पैडिंग हो सकती है, लेकिन इसकी शुरुआत में उचित संरेखण प्राप्त करने के लिए आवश्यक नहीं है।

मानक लेआउट के लिए आवश्यकताओं को यहाँ उल्लेख कर रहे हैं: StandardLayoutType

यह निश्चित रूप से घोंसले के माध्यम से लागू किया जा सकता है। बिट 0 फ़ील्ड के लिए को छोड़कर के पहले सदस्य के प्रकार के लिए मानक कोई अपवाद नहीं करता है। आईई .:

class X 
{ 
public: 
    int x; 
}; 

class Y 
{ 
public: 
    X x; 
    int y; 
}; 

Y yobj; 

मानक, &yobj == &yobj.x == &yobj.x.x द्वारा।

+0

+1 .. मैं इसे ढूंढ रहा था * "मानक-लेआउट स्ट्रक्चर ऑब्जेक्ट के लिए एक पॉइंटर, जो कि एक reinterpret_cast का उपयोग करके उपयुक्त रूप से परिवर्तित हो गया है, इसके प्रारंभिक सदस्य को इंगित करता है" *। इसके लिए बहुत बहुत धन्यवाद। – Nawaz

3

बस अपने भ्रम स्पष्ट करने के लिए:

1) पहली सूचक की .Value - परीक्षण की स्मृति स्थान - दूसरा एक (परीक्षण का पहला क्षेत्र) की तरह ही है।
संरचना का पता और उसका पहला क्षेत्र समान होना चाहिए क्योंकि संरचना अपने खेतों के संग्रह दोनों में कुछ भी नहीं है।

enter image description here

तुम भी आगे समझ आसान बनाने के लिए, जिसमें सरणी के पते जाहिर सरणी के पहले तत्व (क्षेत्र) के बराबर हो जाएगा सरणियों के मामले पर विचार कर सकते हैं।

2)। क्या इसका मतलब यह है कि वस्तुओं के पास कोई वास्तविक अद्वितीय स्मृति पता नहीं है, और यह कि एक संरचना या वर्ग के लिए सूचक केवल अपने पहले क्षेत्र को इंगित करता है?
मुझे लगता है कि आप इसे जावा के साथ भ्रमित कर रहे हैं जिसमें वस्तु हमेशा हीप पर आवंटित की जाती है। सी ++ में, स्ट्रक्चर/क्लास को हमेशा स्टैक पर आवंटित किया जाता है जब तक कि यह गतिशील स्मृति आवंटन ('नया' ऑपरेटर का उपयोग करके) जहां ऑब्जेक्ट को ढेर में आवंटित किया जाता है और पॉइंटर चर (स्टैक में) उस ऑब्जेक्ट को ढेर में इंगित करेगा। इसलिए, पूर्व मामले में संरचना परिवर्तक के पास हमेशा इसके पहले तत्व (फ़ील्ड) के समान पता होगा।

आशा है कि मदद करता है।

+1

आह हाँ, मैं शायद जावा के संदर्भ में सोच रहा था। और सरणी समानता बहुत उपयोगी है। – ApproachingDarknessFish

संबंधित मुद्दे