2012-07-09 27 views
19

सिर्फ gdb में निम्नलिखित निरीक्षण किया गया:सी अनुकूलन

char *a[] = {"one","two","three","four"}; 
char *b[] = {"one","two","three","four"}; 
char *c[] = {"two","three","four","five"}; 
char *d[] = {"one","three","four","six"}; 

और मैं निम्नलिखित हो:

(gdb) p a 
$17 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"} 
(gdb) p b 
$18 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"} 
(gdb) p c 
$19 = {0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four", 0x80961b7 "five"} 
(gdb) p d 
$20 = {0x80961a4 "one", 0x80961ac "three", 0x80961b2 "four", 0x80961bc "six"} 

मैं वाकई हैरान है कि स्ट्रिंग संकेत समकक्ष के लिए ही कर रहे हैं हूँ शब्द। मैंने सोचा होगा कि प्रत्येक स्ट्रिंग को अपनी खुद की याददाश्त को स्टैक पर आवंटित किया जाएगा चाहे वह किसी अन्य सरणी में एक स्ट्रिंग के समान था।

क्या यह किसी प्रकार के कंपाइलर अनुकूलन का उदाहरण है या क्या यह इस प्रकार की स्ट्रिंग घोषणा के लिए मानक व्यवहार है?

+1

इस प्रश्न में "स्टैक" भी कहां से आया था? यदि आपने 'a',' b', 'c' और' d' को स्थानीय चर के रूप में घोषित किया है, तो आपको अपने प्रश्न में ऐसा कहना होगा। – AnT

+0

हां - वे स्टैक – bph

+2

हां पर फ़ंक्शन के भीतर घोषित ऑटो अवधि के स्थानीय चर हैं। यह संकलक अनुकूलन का एक उदाहरण है। – Jack

उत्तर

24

इसे "स्ट्रिंग पूलिंग" कहा जाता है। यह माइक्रोसॉफ्ट कंपाइलर्स में वैकल्पिक है, लेकिन जीसीसी में नहीं। यदि आप एमएसवीसी में स्ट्रिंग पूलिंग को बंद करते हैं, तो अलग-अलग सरणी में "समान" तारों को डुप्लिकेट किया जाएगा, और अलग-अलग मेमोरी पते होंगे, और इसलिए आपके स्थिर डेटा के अतिरिक्त (अनावश्यक) 50 या बाइट्स ले जाएंगे।

संपादित करें: gcc वास्तव में एक विकल्प है, -fwritable-strings जो स्ट्रिंग पूलिंग को अक्षम करता है। इस विकल्प का प्रभाव दो गुना है: यह स्ट्रिंग अक्षर को ओवरराइट करने की अनुमति देता है, और स्ट्रिंग पूलिंग को अक्षम करता है। तो, आपके कोड में, इस ध्वज को सेट करने से कुछ हद तक खतरनाक कोड

/* Overwrite the first string in a, so that it reads 'xne'. Does not */ 
/* affect the instances of the string "one" in b or d */ 
*a[0] = 'x'; 
+4

जीसीसी में (कम से कम 4.7) पूलिंग अक्षम करने के लिए एक स्विच -फनो-मर्ज-स्थिरांक है। – dbrank0

+3

@ dbrank0 ध्यान दें कि [gcc अब fwritabe-srings का समर्थन नहीं करता है] (https://gcc.gnu.org/gcc-4.0/changes.html), इन दोनों नोट्स को आपके उत्तर में जोड़ना आदर्श होगा। –

7

(मुझे लगता है कि अपने a, b, c और d स्थानीय चर, जो आपके ढेर से संबंधित उम्मीदों का कारण है के रूप में घोषित कर रहे हैं।) सी में

स्ट्रिंग शाब्दिक स्थिर भंडारण अवधि की है। उन्हें "ढेर पर" आवंटित नहीं किया जाता है। वे हमेशा वैश्विक/स्थिर स्मृति में आवंटित होते हैं और "हमेशा के लिए" रहते हैं, यानी जब तक कार्यक्रम चलता है।

आपके a, b, c और d सरणी स्टैक पर आवंटित किए गए थे। इन सरणी में संग्रहीत पॉइंटर्स स्थिर स्मृति को इंगित करते हैं। इन परिस्थितियों में, समान शब्दों के समान होने के लिए पॉइंटर्स के बारे में असामान्य कुछ भी नहीं है।

चाहे कोई कंपाइलर समान अक्षरों को एक में विलय करेगा, संकलक पर निर्भर करता है। कुछ कंपाइलरों में भी एक विकल्प होता है जो इस व्यवहार को नियंत्रित करता है। स्ट्रिंग अक्षर हमेशा पढ़ने के लिए होते हैं (यही कारण है कि const char * अपने सरणी के लिए टाइप करने का बेहतर विचार है), इसलिए जब तक आप वास्तविक सूचक मूल्यों पर भरोसा नहीं करते हैं, तब तक यह विलय नहीं होता है या नहीं, इससे कोई फर्क नहीं पड़ता है।

पीएस जिज्ञासा से बाहर: भले ही इन स्ट्रिंग अक्षर को ढेर पर आवंटित किया गया हो, फिर भी आप समान शाब्दिकों को एक बार से अधिक "तत्काल" होने की उम्मीद क्यों करेंगे?

+1

बहुत अच्छी चीजें जो वास्तव में चल रही हैं, यह समझाने में बहुत उपयोगी है - इससे मेरी समझ में बहुत मदद मिली, स्ट्रिंग शाब्दिक सामग्री और इसकी संबंधित स्टोरेज अवधि पूरी तरह से समझ में नहीं आया - मैं स्ट्रिंग के बारे में गलत तरीके से सोच रहा था क्योंकि स्टैक – bph

+2

पर स्थानीय चर (स्वचालित) होने के नाते कुछ भी नहीं है जो मुझे पता है कि एक ही स्ट्रिंग के दो (या अधिक) संदर्भ शाब्दिक * आवश्यक * उसी स्मृति स्थान को हल करना चाहिए। संकलक प्रत्येक स्ट्रिंग के लिए भंडारण आवंटित कर सकता है (और कुछ करते हैं), भले ही कुछ "डुप्लिकेट" हों। @ जोश द्वारा वर्णित "स्ट्रिंग पूलिंग" देखें। –

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