c सूचक स्थिर और साथ ही अस्थिर घोषित किया गया




const volatile (6)

उदाहरण के लिए अपने नेटवर्क कार्ड के केवल पढ़ने के लिए एक हार्डवेयर रजिस्टर पर विचार करें।

यह कार्यक्रम के नियंत्रण से बाहर बदल सकता है, इसलिए कंपाइलर को एक रजिस्टर में इसके मूल्य को कैश करने या इसे अनुकूलित करने की अनुमति नहीं है। इस प्रकार, volatile

और यह केवल पढ़ने के लिए है, इसलिए आपको इसे नहीं लिखना चाहिए। इस प्रकार, const

https://code.i-harness.com

पढ़ते समय मैं इस प्रकार की घोषणा और निम्नलिखित पंक्ति में आया था -

const volatile char *p=(const volatile char *) 0x30;

P का मान केवल बाहरी स्थितियों से बदला जाता है

मुझे नहीं मिलता कि बाहरी परिस्थितियां क्या हैं। और यह भी कि इस प्रकार की घोषणा का व्यावहारिक उपयोग क्या है?


पहले, मुझे C11 मानक, अध्याय .36.7.3 से उदाहरण उद्धृत करते हैं, टाइप करें क्वालीफायर

घोषित की गई कोई वस्तु

extern const volatile int real_time_clock;

हार्डवेयर के माध्यम से परिवर्तनीय हो सकता है, लेकिन उसे बढ़ाया, या घटाया नहीं जा सकता है।

इसके अलावा, संबंधित फुटनोट (134),

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

इसका मतलब है, चर का मान हार्डवेयर (मेमोरी-मैपिंग के माध्यम से) द्वारा संशोधित किया जा सकता है, लेकिन "प्रोग्रामेटिक रूप से" संशोधित नहीं किया जा सकता है।

तो, लाभ यहाँ दो गुना है,

  • जब भी उपयोग किया जाने वाला मूल्य, मेमोरी से कैश किया जाएगा (कैश-आईएनजी की अनुमति नहीं है), आपको नवीनतम अद्यतन मूल्य (यदि अपडेट किया गया है) दे रहा है।
  • मान, परिवर्तित नहीं किया जा सकता ( लिखित रूप से ) प्रोग्राम द्वारा जानबूझकर या अनजाने में।

हम लेख का परिचय वाष्पशील खोजशब्द से कर सकते हैं जो कहता है:

जब भी इसका मूल्य अप्रत्याशित रूप से बदल सकता है, तब एक परिवर्तनशील को अस्थिर घोषित किया जाना चाहिए। व्यवहार में, केवल तीन प्रकार के परिवर्तन हो सकते हैं:

  • मेमोरी-मैपेड परिधीय रजिस्टर
  • ग्लोबल वेरिएबल्स को एक सर्विस सर्विस रूटीन द्वारा संशोधित किया गया है
  • एक बहु-थ्रेडेड अनुप्रयोग के भीतर वैश्विक चर

तथा:

एंबेडेड सिस्टम में वास्तविक हार्डवेयर होते हैं, आमतौर पर परिष्कृत परिधीय के साथ। इन परिधीयों में रजिस्टर होते हैं जिनके मान प्रोग्राम प्रवाह में अतुल्यकालिक रूप से बदल सकते हैं। एक बहुत ही सरल उदाहरण के रूप में, 0x1234 पते पर 8-बिट स्थिति रजिस्टर पर विचार करें। यह आवश्यक है कि आप तब तक स्थिति रजिस्टर को प्रदूषित करें जब तक कि यह शून्य न हो जाए। गलत और गलत कार्यान्वयन इस प्रकार है:

UINT1 * ptr = (UINT1 *) 0x1234;

// Wait for register to become non-zero.
while (*ptr == 0);
// Do something else.

जैसे ही आप ऑप्टिमाइज़र चालू करते हैं, यह लगभग निश्चित रूप से विफल हो जाएगा, क्योंकि कंपाइलर असेंबली भाषा उत्पन्न करेगा जो कुछ इस तरह दिखता है:

mov    ptr, #0x1234     mov    a, @ptr loop     bz    loop

कास्ट का कहना है कि आपका प्रोग्राम वैरिएबल को नहीं बदलेगा लेकिन जैसा कि बाहर के लेख में बताया गया है और अस्थिरता इसे दूर करने से रोकती है।


const एक वेरिएबल को स्थिर नहीं बनाता है। यह सिर्फ कंपाइलर को कुछ लिखने के लिए मना कर देता है। यह अभी भी चर (उदाहरण के लिए कास्ट-कास्ट पॉइंटर्स के माध्यम से) में लिखना संभव है।

आप const को कोडिंग गलतियों से सुरक्षा के रूप में देख सकते हैं।

यह घोषणा सुनिश्चित करती है कि आप अनजाने में p को नहीं लिखेंगे, जबकि संकलक को एक्सेस (कैश, ऑर्डर आउट से बाहर निकलने के लिए अनुकूलन नहीं) (), ...) को बताएं क्योंकि कोई बाहरी घटना p में लिख सकती है।


const कहता है कि आपके प्रोग्राम का प्रवाह p द्वारा इंगित किए गए को संशोधित करने वाला नहीं है। सूचक को निष्क्रिय करने के बाद मूल्य को संशोधित करने का कोई भी प्रयास एक संकलन-समय त्रुटि के परिणामस्वरूप होगा:

*p = 'A'; // will not compile

ध्यान दें कि यह एक विशेष रूप से मजबूत अनुबंध नहीं है; 0x30 स्थान पर मान अभी भी एक aliasing नॉन-कास्ट पॉइंटर के माध्यम से बदला जा सकता है, p :

volatile char *q = 0x30;
*q = 'A'; // will compile

इस कॉन्ट्रैक्ट को तोड़ने का एक और तरीका है कि p से const को दूर करके:

*(volatile char *) p = 'A'; // will compile

volatile , हालांकि, किसी भी संशोधन को बाहर नहीं करता है जो किसी अन्य धागे, कर्नेल, एक अतुल्यकालिक सिग्नल हैंडलर या एक बाहरी डिवाइस के कारण हो सकता है जिसकी समान मेमोरी स्पेस तक पहुंच है। इस तरह संकलक गलत धारणा नहीं बना सकता है कि p द्वारा p गए मूल्य में बदलाव नहीं होता है और इसे संदर्भित होने पर हर बार इसे मेमोरी से लोड किया जाएगा:

/*
 The character at 0x30 will be read on every iteration,
 even if the compiler has proven that the program itself
 doesn't modify the value at that address.
*/
while (*p) {
    ...
}

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


* const वाष्पशील चार * p = (कास्ट वाष्पशील चार ) 0x30;
इसका क्या मतलब है: पी के मूल्य को केवल बाहरी परिस्थितियों द्वारा बदल दिया जाता है।

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

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

आपके सॉफ़्टवेयर के दृष्टिकोण से, यह दिखाता है:







volatile