2012-09-12 5 views
8

जब मैं संकलन और रन मेरी लिनक्स x86_64 मशीन, जीसीसी द्वारा संकलित पर सी कार्यक्रम निम्नलिखित:जीसीसी द्वारा संग्रहीत स्ट्रिंग स्थिरांक कहां से हैं और जहां से इन पॉइंटर्स मैप किए जाते हैं?

बराबर 0x40064c 0x40064c

मैं:

#include <stdio.h> 

int main(void) 
{ 
    char *p1 = "hello";    // Pointers to strings 
    char *p2 = "hello";    // Pointers to strings 
    if (p1 == p2) {     // They are equal 
    printf("equal %p %p\n", p1, p2); // equal 0x40064c 0x40064c 
             // This is always the output on my machine 
    } 
    else { 
    printf("NotEqual %p %p\n", p1, p2); 
    } 
} 

मैं हमेशा के रूप में आउटपुट प्राप्त समझें कि तार स्थिर तालिका में संग्रहीत हैं लेकिन गतिशील आवंटित स्मृति की तुलना में पता बहुत कम है।

निम्नलिखित कार्यक्रम के साथ तुलना करें:

#include <stdio.h> 

int main(void) 
{ 
    char p1[] = "hello";    // char arrar 
    char p2[] = "hello";    // char array 
    if (p1 == p2) { 
    printf("equal %p %p\n", p1, p2); 
    } 
    else {        // Never equal 
    printf("NotEqual %p %p\n", p1, p2); // NotEqual 0x7fff4b25f720 0x7fff4b25f710 
             // Different pointers every time 
             // Pointer values too large 
    } 
} 

दो संकेत बराबर नहीं हैं, क्योंकि इन दो सरणियों जो स्वतंत्र रूप से हेरफेर किया जा सकता है।

मैं जानना चाहता हूं कि जीसीसी इन दो कार्यक्रमों के लिए कोड कैसे उत्पन्न करता है और निष्पादन के दौरान उन्हें स्मृति में कैसे मैप किया जाता है। चूंकि यह पहले ही दस्तावेज किया जाएगा, इसलिए कई बार दस्तावेज़ों के किसी भी लिंक का स्वागत है।

+0

आप हमेशा डिस्सेप्लर पर चोटी कर सकते हैं। यह विकसित करने के लिए एक अच्छा कौशल है, आपको भविष्य में इसे फिर से करने की आवश्यकता होगी। –

+0

आपके उदाहरण कोड में केवल दो स्ट्रिंग हैं: 'बराबर% पी% पी \ n' और' NotEqual% p% p \ n'। 'p1' और 'p2' केवल कुछ मानों के लिए प्रारंभ किए गए वर्ण सरणी चर हैं, जिन्हें तब स्ट्रिंग के रूप में उपयोग किया जाता है। विशेष रूप से, आप अभी भी 'पी 1 [0] =' एच 'कर सकते हैं; पी 2 [0] = 'जे'; उदाहरण के लिए, किसी भी मुद्दे के बिना। यदि आप स्ट्रिंग स्थिरांक होने के लिए 'p1' और' p2' चाहते थे, तो 'स्थिर कॉन्स char p1 [] = "हैलो" का उपयोग करें; '। कम से कम जीसीसी-4.6.3 स्थानीय कॉन्स एरे को वैरिएबल के रूप में मानता है, न केवल वास्तविक पढ़ने-योग्य स्थिरांक, इसलिए 'स्थिर' की आवश्यकता होती है। और यह तारों को जोड़ता नहीं है, इसलिए दोनों में अलग-अलग पॉइंटर्स होते हैं। आप किस कंपाइलर का उपयोग कर रहे हैं? –

उत्तर

11

दोनों ही मामलों संकलक सिर्फ एक बार स्ट्रिंग "hello" की वास्तविक बाइट्स का उत्सर्जन करता है, कार्यक्रम के .rodata खंड में में (rodataके लिए खड़ा है केवल डेटा पढ़ें)।

वे वास्तव में निष्पादन योग्य फ़ाइल से स्मृति में सीधे मैप किए जाते हैं, कुछ हद तक कोड अनुभाग के समान होते हैं। यही कारण है कि वे गतिशील आवंटित लोगों से बहुत अलग हैं।

तब:

char *p = "hello"; 

बस इस (केवल पढ़ने के लिए) डेटा के पते पर p initializes। और स्पष्ट रूप से:

char *q = "hello"; 

बहुत ही पते हो जाता है। इसे स्ट्रिंग पूलिंग कहा जाता है और यह संकलक का वैकल्पिक लोकप्रिय अनुकूलन है।

लेकिन आप लिखते हैं जब:

char p[] = "hello"; 

यह शायद कुछ इस तरह उत्पन्न करेगा:

char p[6]; 
memcpy(p, "hello", 6); 

"hello" वास्तव में रीड-ओनली जमा तार का पता होने के नाते।

memcpy पर कॉल केवल चित्रण उद्देश्यों के लिए है। फ़ंक्शन कॉल के बजाए कॉपी इनलाइन के लिए यह बहुत अच्छा हो सकता है।

तो बाद में आप करते हैं:

char q[] = "hello"; 

यह एक और सरणी और एक अन्य memcpy() परिभाषित करेगा। एक ही डेटा, लेकिन विभिन्न पते।

लेकिन जहां ये सरणी चर रहते हैं? अच्छा, यह निर्भर करता है।

  • यदि वे स्थानीय, गैर स्थैतिक, चर हैं: ढेर में।
  • यदि वे वैश्विक चर हैं: तो वे निष्पादन योग्य के .data अनुभाग में होंगे, और वे पहले से मौजूद सही वर्णों के साथ वहां सहेजे जाएंगे, इसलिए रन समय में memcpy की आवश्यकता नहीं है। जो अच्छा है, क्योंकि memcpy को main से पहले निष्पादित करना होगा।
  • यदि वे स्थानीय स्थैतिक चर हैं: बिल्कुल वैश्विक चर के समान ही। वे दोनों को variables of static duration या ऐसा कुछ कहा जाता है।

प्रलेखन लिंक के बारे में, क्षमा करें, मुझे किसी के बारे में पता नहीं है।

लेकिन यदि आप स्वयं प्रयोग कर सकते हैं तो दस्तावेज़ीकरण की आवश्यकता कौन है? इसके लिए सबसे अच्छा उपकरण objdump है, यह प्रोग्राम को अलग कर सकता है, डेटा अनुभागों को डंप कर सकता है और बहुत कुछ!

मुझे उम्मीद है कि यह आपके सवालों का जवाब देगा ...

+0

'objdump' से कहीं अधिक सरल है, केवल असेंबलर का उत्पादन करने के लिए '-c' के बजाय' -S' का उपयोग करें। –

+0

@ जेन्सगस्टेड: अनुमोदित। मैं सिर्फ 'objdump' के उत्पादन में उपयोग किया जाता है। – rodrigo

+0

इसे 'memcpy'' की आवश्यकता भी नहीं होनी चाहिए और "हेलो" को सीधे स्टैक शब्दों के रूप में स्टोर करना होगा। – oldrinb

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