2009-11-10 17 views
19

मैंने सुना है कि सी में, अगर मैंसी में केवल पढ़ने योग्य मेमोरी कैसे लागू की जाती है?

char *s = "hello world". 

करते हैं "हैलो दुनिया" वास्तव में केवल पढ़ने के लिए स्मृति में संग्रहीत किया जाता है।

मैं केवल पढ़ने योग्य स्मृति के बारे में इतना स्पष्ट नहीं हूं। स्पष्टीकरण क्या है? क्या यह कंपाइलर को ध्वज की तरह है जो संकलक को उस खंड में लिखने के लिए कहता है?

+1

आप एक संदर्भ है? मुझे लगता है कि आपका मतलब हो सकता है: const char * s = "हैलो वर्ल्ड"। –

+3

यह स्पष्ट नहीं है कि सभी प्रोसेसर आर्किटेक्चर सुरक्षित स्मृति का समर्थन करते हैं। – jldupont

+1

@ जेम्स ब्लैक: ओपी स्पष्ट रूप से स्ट्रिंग शाब्दिक 'हैलो वर्ल्ड "के बारे में बात कर रहा है, जिसे वास्तव में केवल पढ़ने योग्य स्मृति में संग्रहीत किया जा सकता है, भले ही पॉइंटर घोषित किया जाए। – AnT

उत्तर

27

C language की एक विशेषता लेकिन संकलक की एक विशेषता नहीं है यही कारण है कि/लिंकर और ऑपरेशन सिस्टम एक साथ काम कर रहे हैं।

जब आप इस तरह के कोड निम्न होता संकलन:

  • संकलक केवल पढ़ने के लिए डेटा अनुभाग में स्ट्रिंग डाल देंगे।

  • लिंकर ऐसे सभी-पढ़ने वाले अनुभागों में सभी डेटा एकत्र करता है और उन्हें एक सेगमेंट में रखता है। यह सेगमेंट निष्पादन योग्य फ़ाइल में रहता है और इसे "केवल पढ़ने" -ट्रिब्यूट के साथ फ़्लैग किया जाता है।

  • अब ऑपरेशन सिस्टम निष्पादन योग्य लोडर आता है। यह निष्पादन योग्य लोड करता है (या इसे अधिक सटीक होने के लिए स्मृति में मानचित्र करता है)। एक बार ऐसा करने के बाद, लोडर अनुभागों पर चलता है और प्रत्येक सेगमेंट के लिए एक्सेस-अनुमति सेट करता है। केवल पढ़ने के लिए डेटा सेगमेंट के लिए यह संभवतः कोड-निष्पादन अक्षम और पहुंच लिखने की संभावना है। कोड (उदाहरण के लिए, आपके फ़ंक्शन) निष्पादित अधिकार प्राप्त करते हैं लेकिन कोई लेखन पहुंच नहीं होती है। स्थिर चर जैसे साधारण डेटा को पढ़ने और लिखने के लिए और अधिक पढ़ें ...

अब आधुनिक ऑपरेशन सिस्टम ऐसा करते हैं।

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

+0

निरंतर परिवर्तनीय भी "हैलो वर्ल्ड" के समान अनुभाग डालता है? (उदा।: Int int = 6) – root

+0

"यह निर्भर करता है"। एकमात्र चीज जो आप निश्चित रूप से एक कॉन्स्ट int के बारे में कह सकते हैं वह यह है कि यदि आप इसे संशोधित करने का प्रयास करते हैं तो संकलक नैदानिक ​​संदेश उत्पन्न करेगा। इसे केवल पढ़ने के लिए खंड में संग्रहीत किया जा सकता है, या इसे कभी भी संग्रहीत नहीं किया जा सकता है, और सीधे इसका उपयोग करने वाले निर्देशों में निरंतर के रूप में एन्कोड किया जा सकता है। –

+0

@tsubasa - शायद नहीं, और निश्चित रूप से नहीं यदि 'a' एक स्थानीय है। लेकिन जो कुछ भी जवाब है, वह ओएस और लोडर पर भी निर्भर करेगा। –

3

ट्रू रीड-ओनली मेमोरी ओएस के मेमोरी सबसिस्टम द्वारा कार्यान्वित किया जाता है। ओएस कुछ पृष्ठों को केवल पढ़ने के लिए चिह्नित कर सकता है।

बाइनरी में, कंपाइलर ओएस को बता सकता है कि निष्पादन योग्य के कुछ हिस्सों को केवल पढ़ने के लिए बनाम रीड-राइट मेमोरी पेजों में रखा जाना चाहिए।

+1

hmmm ... वास्तविक स्मृति सुरक्षा प्रोसेसर स्तर पर लागू की जाती है। – jldupont

+0

@jldupont: स्मृति सुरक्षा वास्तव में हार्डवेयर स्तर (x86 में कम से कम) पर लागू होती है, लेकिन प्रारंभिक सेटअप ओएस द्वारा किया जाता है, यानी।यह ओएस है कि * अंक * केवल पढ़ने के लिए पेज, और फिर हार्डवेयर ओएस द्वारा स्थापित केवल पढ़ने वाले अंक लागू करता है। – AnT

+0

@AndreyT: बेशक ... मेरा बिंदु @ आर सैमुअल के संबंध में था। ** हार्डवेयर ** सहायता के बिना, सॉफ़्टवेयर स्तर पर ऐसा कोई भी कर सकता है। – jldupont

6

निष्पादन योग्य में दो भाग होते हैं: एक। डेटा अनुभाग, जिसमें वैश्विक चर शामिल हैं, और एक .text अनुभाग, जिसमें वास्तविक मशीन कोड होता है।

स्ट्रिंग्स को। डेटा अनुभाग में रखा गया है। जब सी "हैलो वर्ल्ड" देखता है तो सी क्या करता है, यह स्ट्रिंग "हैलो वर्ल्ड" को निष्पादन योग्य में रखता है, और प्रोग्राम में "हैलो वर्ल्ड" के उदाहरण को उस पते के साथ बदलता है जहां वह स्ट्रिंग लोड हो जाती है।

कहा करने के बाद कि, मुझे यकीन है कि क्यों यह केवल पढ़ने के लिए है नहीं कर रहा हूँ - सैद्धांतिक रूप से एक कार्यक्रम का अपना स्मृति को संशोधित करने में सक्षम होना चाहिए ..

+2

सभी प्रोसेसर और ऑपरेटिंग सिस्टम स्व-संशोधित कोड का समर्थन नहीं करते हैं। वास्तव में, अधिकांश आधुनिक ऑपरेटिंग सिस्टम में सुरक्षा सुविधा के रूप में स्वयं-संशोधित कोड के विरुद्ध सुरक्षा होती है। – Crashworks

+0

स्ट्रिंग अक्षर, क्योंकि उन्हें संशोधित करने की आवश्यकता नहीं है, अक्सर टेक्स्ट अनुभाग में संग्रहीत और संग्रहीत किया जा सकता है। – caf

2

लिनक्स में ऐसा करने का एक उदाहरण मार्क मिशेल, जेफरी ओलहम और एलेक्स सैमुअल द्वारा page 179 of Advanced Linux Programming पर है।

+0

बहुत बढ़िया किताब यह है .. 2 साल के बाद भी :) ... – bsoundra

0

आप की तरह

s[4] = '0'; 

कुछ कोशिश करते हैं और देख सकते हैं अगर यह कहते हैं, "हैलो w0rld" जब आप

puts(s); 

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

1

जैसा कि अन्य लोगों ने उल्लेख किया है, क्या निरंतर तारों की सामग्री केवल पढ़ने वाली स्मृति में संग्रहीत होती है ऑपरेटिंग द्वारा निर्धारित की जाती है प्रणाली, कंपाइलर, और चिप वास्तुकला।

अधिक सटीक रूप से, सी मानक निर्दिष्ट करता है कि उद्धृत तारों को "कॉन्स्ट char []" प्रकार (या उस प्रभाव के लिए शब्द, मेरे पास मानक नहीं है) माना जाता है।

कोई भी कोड जो इस तरह की स्ट्रिंग की सामग्री को संशोधित करने का प्रयास करता है, वह अनिर्धारित व्यवहार का आह्वान कर रहा है। इसका मतलब है कि उस बिंदु पर सचमुच कुछ भी हो सकता है, और संकलक के प्रदाता को यह भी दस्तावेज करने की आवश्यकता नहीं है कि क्या हो सकता है।

प्रैक्टिस में, इसका मतलब है कि एक सी या सी ++ प्रोग्राम जो पोर्टेबल बनना चाहता है उसे निरंतर तारों को संशोधित करने से बचना है।

सामान्य रूप से, कंपाइलर आपको "कॉन्स्ट" चर की सामग्री को संशोधित करने की अनुमति नहीं देगा, इसलिए आप ज्यादातर मामलों में "केवल" का अर्थ "कॉन्स्ट" मान सकते हैं। दुर्भाग्यवश, ऐतिहासिक कारणों से मुख्य रूप से char * और const char * के लिए एक विशेष अपवाद है।

char *x = "Hello, World"; 
*x = 'h'; 

, त्रुटि या चेतावनी के बिना संकलित कर देगा, भले ही यह अपरिभाषित व्यवहार का आह्वान: यह इस तरह है कि कोड का मतलब है।

0

जब आप char s[10]="sneha" लिखते हैं; आप अपनी ऑब्जेक्ट फ़ाइल में 10 बाइट स्टोरेज स्पेस आवंटित कर रहे हैं (स्मृति नहीं, स्मृति केवल आपके प्रोग्राम को निष्पादित करते समय चित्र में आती है)। यह स्मृति की स्थिर आवंटन (संकलन समय पर) है।

लेकिन जब आप char *s="sneha"; लिखते हैं तो आप "sneha" स्टोर करने के लिए किसी भी संग्रहण स्थान आवंटित नहीं कर रहे हैं। यह केवल पढ़ने के खंड में संग्रहीत किया जाएगा। लेकिन पॉइंटर s विभिन्न खंडों में संग्रहीत किया जाता है, जहां इसे घोषित किया जाता है। लेकिन यह केवल डेटा "sneha" पढ़ने के लिए इंगित कर रहा है। तो यदि आप इसे लिखने का प्रयास करते हैं तो आपको सेगमेंटेशन गलती मिल जाएगी।

उदाहरण के लिए:

char *s[10]="sneha"; 
s[1]="N"; 
printf("%s",s); // you expecting output sNeha, 
       // but you get a seg fault since it is ONLY DATA 
संबंधित मुद्दे