C Language
क्वालिफायर टाइप करें
खोज…
टिप्पणियों
टाइप क्वालिफायर वे कीवर्ड होते हैं जो एक प्रकार के बारे में अतिरिक्त शब्दार्थ का वर्णन करते हैं। वे प्रकार के हस्ताक्षर का एक अभिन्न अंग हैं। वे एक घोषणा के सबसे ऊपरी स्तर पर (सीधे पहचानकर्ता को प्रभावित करने वाले) या उप-स्तरों पर (केवल संकेत करने वाले मूल्यों को प्रभावित करते हुए) दोनों को प्रदर्शित कर सकते हैं:
कीवर्ड | टिप्पणियों |
---|---|
const | घोषित ऑब्जेक्ट के उत्परिवर्तन (सबसे ऊपरी स्तर पर दिखाई देने से) को रोकता है या इंगित किए गए मान के म्यूटेशन को रोकता है (एक पॉइंटर उपप्रकार के बगल में आने से)। |
volatile | संकलक को सूचित करता है कि घोषित ऑब्जेक्ट (सबसे ऊपरी स्तर पर) या पॉइंट-टू वैल्यू (पॉइंटर सबटिप में) बाहरी परिस्थितियों के परिणामस्वरूप अपना मान बदल सकता है, न कि केवल प्रोग्राम कंट्रोल फ्लो के परिणामस्वरूप। |
restrict | एक अनुकूलन संकेत, केवल संकेत करने के लिए प्रासंगिक। इस आशय की घोषणा करता है कि सूचक के जीवनकाल के लिए, किसी अन्य पॉइंटर्स का उपयोग उसी पॉइंट-टू-ऑब्जेक्ट तक पहुंचने के लिए नहीं किया जाएगा। |
भंडारण वर्ग विनिर्देशक ( static
, extern
, auto
, register
) के संबंध में टाइप क्वालिफ़ायर का क्रम, प्रकार संशोधक ( signed
, unsigned
, short
, long
) और प्रकार विनिर्देशक ( int
, char
, double
, आदि) लागू नहीं है, लेकिन अच्छा अभ्यास उन्हें पूर्वोक्त क्रम में रखना है:
static const volatile unsigned long int a = 5; /* good practice */
unsigned volatile long static int const b = 5; /* bad practice */
शीर्ष स्तर की योग्यता
/* "a" cannot be mutated by the program but can change as a result of external conditions */
const volatile int a = 5;
/* the const applies to array elements, i.e. "a[0]" cannot be mutated */
const int arr[] = { 1, 2, 3 };
/* for the lifetime of "ptr", no other pointer could point to the same "int" object */
int *restrict ptr;
सूचक उपप्रकार योग्यता
/* "s1" can be mutated, but "*s1" cannot */
const char *s1 = "Hello";
/* neither "s2" (because of top-level const) nor "*s2" can be mutated */
const char *const s2 = "World";
/* "*p" may change its value as a result of external conditions, "**p" and "p" cannot */
char *volatile *p;
/* "q", "*q" and "**q" may change their values as a result of external conditions */
volatile char *volatile *volatile q;
अनम्य (कांस्टेबल) चर
const int a = 0; /* This variable is "unmodifiable", the compiler
should throw an error when this variable is changed */
int b = 0; /* This variable is modifiable */
b += 10; /* Changes the value of 'b' */
a += 10; /* Throws a compiler error */
const
योग्यता का मतलब केवल यह है कि हमारे पास डेटा को बदलने का अधिकार नहीं है। इसका मतलब यह नहीं है कि मूल्य हमारी पीठ के पीछे नहीं बदल सकता है।
_Bool doIt(double const* a) {
double rememberA = *a;
// do something long and complicated that calls other functions
return rememberA == *a;
}
अन्य कॉलों के निष्पादन के दौरान *a
बदल सकता है, और इसलिए यह फ़ंक्शन false
या true
हो सकता true
।
चेतावनी
const
योग्यता के साथ चर अभी भी संकेत का उपयोग कर बदला जा सकता है:
const int a = 0;
int *a_ptr = (int*)&a; /* This conversion must be explicitly done with a cast */
*a_ptr += 10; /* This has undefined behavior */
printf("a = %d\n", a); /* May print: "a = 10" */
लेकिन ऐसा करना एक त्रुटि है जो अपरिभाषित व्यवहार की ओर जाता है। यहां कठिनाई यह है कि यह सरल उदाहरणों में अपेक्षा के अनुसार व्यवहार कर सकता है, लेकिन फिर कोड बढ़ने पर गलत हो जाता है।
अस्थिर चर
volatile
कीवर्ड संकलक को बताता है कि प्रोग्राम नियंत्रण प्रवाह के परिणामस्वरूप न केवल बाहरी परिस्थितियों के परिणामस्वरूप चर का मूल्य बदल सकता है।
संकलक किसी भी चीज का अनुकूलन नहीं करेगा जिसका अस्थिर चर के साथ क्या करना है।
volatile int foo; /* Different ways to declare a volatile variable */
int volatile foo;
volatile uint8_t * pReg; /* Pointers to volatile variable */
uint8_t volatile * pReg;
वाष्पशील चरों के उपयोग के दो मुख्य कारण हैं:
- स्मृति-मैप किए गए I / O रजिस्टरों वाले हार्डवेयर के साथ इंटरफ़ेस करने के लिए।
- प्रोग्राम कंट्रोल फ्लो के बाहर संशोधित किए गए वेरिएबल्स का उपयोग करते समय (जैसे, इंटरप्ट सर्विस रूटीन में)
आइए इस उदाहरण को देखें:
int quit = false;
void main()
{
...
while (!quit) {
// Do something that does not modify the quit variable
}
...
}
void interrupt_handler(void)
{
quit = true;
}
संकलक को अनुमति दी जाती है कि लूप को quit
चर को संशोधित न करें और लूप को एक अंतहीन while (true)
लूप में बदल दें। यहां तक कि अगर SIGINT
और SIGTERM
लिए सिग्नल हैंडलर पर quit
वैरिएबल सेट किया गया है, तो कंपाइलर को यह पता नहीं है।
volatile
रूप में quit
घोषणा करने से कंपाइलर को लूप को ऑप्टिमाइज़ न करने के लिए कहा जाएगा और समस्या हल हो जाएगी।
हार्डवेयर तक पहुँचने के दौरान भी यही समस्या होती है, जैसा कि हम इस उदाहरण में देखते हैं:
uint8_t * pReg = (uint8_t *) 0x1717;
// Wait for register to become non-zero
while (*pReg == 0) { } // Do something else
ऑप्टिमाइज़र का व्यवहार चर के मूल्य को एक बार पढ़ना है, इसे फिर से पढ़ना नहीं है, क्योंकि मूल्य हमेशा समान रहेगा। तो हम एक अनंत लूप के साथ समाप्त होते हैं। संकलक को वह करने के लिए बाध्य करने के लिए जो हम चाहते हैं, हम घोषणा को संशोधित करते हैं:
uint8_t volatile * pReg = (uint8_t volatile *) 0x1717;