खोज…


परिचय

वेरिएबल या फंक्शन के स्कोप को सेट करने के लिए एक स्टोरेज क्लास का उपयोग किया जाता है। एक चर के भंडारण वर्ग को जानकर, हम कार्यक्रम के रन-टाइम के दौरान उस चर के जीवन-समय को निर्धारित कर सकते हैं।

वाक्य - विन्यास

  • [ऑटो | रजिस्टर | स्टेटिक | एक्सटर्नल] <डेटा प्रकार> <परिवर्तनीय नाम> [= <मूल्य>];

  • [स्टेटिक _Thread_local | एक्सटर्न _Thread_local | _Thread_local] <Data type> <Variable name> [= <value>]; / * के बाद से = = C11 * /

  • उदाहरण:

  • typedef int foo ;

  • बाहरी int foo [2];

टिप्पणियों

संग्रहण वर्ग विनिर्देशक वे खोजशब्द हैं जो किसी घोषणा के शीर्ष-स्तरीय प्रकार के बगल में दिखाई दे सकते हैं। इन कीवर्ड्स का उपयोग घोषित ऑब्जेक्ट की स्टोरेज अवधि और लिंकेज को प्रभावित करता है, यह इस बात पर निर्भर करता है कि यह फाइल स्कोप पर है या ब्लॉक स्कोप में:

कीवर्ड भंडारण अवधि कड़ी टिप्पणियों
static स्थिर अंदर का फ़ाइल स्कोप पर ऑब्जेक्ट्स के लिए आंतरिक लिंकेज सेट करता है; ब्लॉक दायरे में वस्तुओं के लिए स्थिर भंडारण अवधि निर्धारित करता है।
extern स्थिर बाहरी फ़ाइल स्कोप पर परिभाषित ऑब्जेक्ट के लिए लागू और इसलिए निरर्थक, जिसमें एक इनिशलाइज़र भी है। जब एक आरंभिक के बिना फ़ाइल दायरे में एक घोषणा में उपयोग किया जाता है, तो संकेत मिलता है कि परिभाषा किसी अन्य अनुवाद इकाई में पाई जानी है और लिंक-टाइम पर हल हो जाएगी।
auto स्वचालित असंगत ब्लॉक दायरे में घोषित वस्तुओं के लिए लागू और इसलिए निरर्थक।
register स्वचालित असंगत केवल स्वचालित भंडारण अवधि वाली वस्तुओं के लिए प्रासंगिक। एक संकेत प्रदान करता है कि चर को एक रजिस्टर में संग्रहीत किया जाना चाहिए। थोपा हुआ अवरोध यह है कि इस तरह की वस्तु पर आपरेटर के "एकता" & "पते" का उपयोग नहीं किया जा सकता है, और इसलिए वस्तु को अलग नहीं किया जा सकता है।
typedef असंगत असंगत व्यवहार में स्टोरेज क्लास निर्दिष्ट नहीं है, लेकिन एक वाक्यात्मक दृष्टिकोण से एक की तरह काम करता है। अंतर केवल इतना है कि घोषित पहचानकर्ता एक वस्तु के बजाय एक प्रकार है।
_Thread_local धागा बाहरी आंतरिक धागा भंडारण अवधि का प्रतिनिधित्व करने के लिए, C11 में प्रस्तुत किया गया है। यदि ब्लॉक स्कोप में उपयोग किया जाता है, तो इसमें extern या static भी शामिल होगा।

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

शीर्ष-स्तरीय प्रकार विनिर्देशक ( int , unsigned , short , इत्यादि) के संबंध में भंडारण वर्ग के विनिर्देशक का क्रम और शीर्ष-स्तरीय प्रकार के क्वालिफायर ( const , volatile ) लागू नहीं होते हैं, इसलिए ये दोनों घोषणाएँ मान्य हैं:

int static const unsigned a = 5; /* bad practice */
static const unsigned int b = 5; /* good practice */

हालाँकि, इसे स्टोरेज क्लास स्पेसर्स को पहले रखने के लिए एक अच्छा अभ्यास माना जाता है, फिर किसी भी प्रकार के क्वालिफायर, फिर टाइप स्पेसियर ( void , char , int , signed long , unsigned long long , long double ...)।

सभी भंडारण वर्ग विनिर्देशक एक निश्चित दायरे में वैध नहीं हैं:

register int x; /* legal at block scope, illegal at file scope */
auto int y; /* same */

static int z; /* legal at both file and block scope */
extern int a; /* same */

extern int b = 5; /* legal and redundant at file scope, illegal at block scope */

/* legal because typedef is treated like a storage class specifier syntactically */
int typedef new_type_name;

भंडारण अवधि

भंडारण अवधि स्थिर या स्वचालित हो सकती है। एक घोषित वस्तु के लिए, यह इसके दायरे और भंडारण वर्ग के निर्दिष्ट के आधार पर निर्धारित किया जाता है।

स्थैतिक भंडारण अवधि

स्थैतिक भंडारण अवधि के साथ चर पूरे कार्यक्रम के पूरे निष्पादन में रहते हैं और फाइल स्कोप ( static साथ या बिना) और ब्लॉक स्कोप ( static रूप से लगाकर) दोनों में घोषित किए जा सकते हैं। वे आमतौर पर प्रोग्राम स्टार्टअप पर ऑपरेटिंग सिस्टम द्वारा आवंटित और आरंभ किए जाते हैं, जब प्रक्रिया समाप्त हो जाती है। व्यवहार में, निष्पादन योग्य स्वरूपों में इस तरह के चर ( data , bss और rodata ) के लिए समर्पित अनुभाग bss और फ़ाइल से इन सभी वर्गों को निश्चित सीमा पर स्मृति में मैप किया जाता है।

धागा भंडारण अवधि

C11

इस भंडारण अवधि को C11 में पेश किया गया था। यह पहले C मानकों में उपलब्ध नहीं था। कुछ संकलक समान शब्दार्थ के साथ एक गैर-मानक विस्तार प्रदान करते हैं। उदाहरण के लिए, gcc __thread का समर्थन करता है __thread उपयोग पहले C मानकों में किया जा सकता है जिसमें _Thread_local नहीं था।

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

स्वचालित संग्रहण अवधि

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

विशिष्ट कार्यान्वयन में, स्वचालित चर एक फ़ंक्शन के स्टैक फ्रेम में या रजिस्टरों में कुछ ऑफसेट पर स्थित होते हैं।

बाहरी और आंतरिक संबंध

लिंकेज केवल फ़ाइल दायरे में घोषित वस्तुओं (कार्यों और चर) के लिए प्रासंगिक है और विभिन्न अनुवाद इकाइयों में उनकी दृश्यता को प्रभावित करता है। बाहरी लिंकेज वाली वस्तुएं हर दूसरी अनुवाद इकाई में दिखाई देती हैं (बशर्ते कि उचित घोषणा शामिल हो)। आंतरिक लिंकेज वाली वस्तुएं अन्य अनुवाद इकाइयों के संपर्क में नहीं आती हैं और केवल अनुवाद इकाई में उपयोग की जा सकती हैं जहां वे परिभाषित हैं।

typedef

मौजूदा प्रकार के आधार पर एक नए प्रकार को परिभाषित करता है। इसका सिंटैक्स मिरर डिक्लेरेशन का है।

/* Byte can be used wherever `unsigned char` is needed */
typedef unsigned char Byte;

/* Integer is the type used to declare an array consisting of a single int */
typedef int Integer[1];

/* NodeRef is a type used for pointers to a structure type with the tag "node" */
typedef struct node *NodeRef;

/* SigHandler is the function pointer type that gets passed to the signal function. */
typedef void (*SigHandler)(int);

जबकि तकनीकी रूप से एक भंडारण वर्ग नहीं है, एक कंपाइलर इसे एक के रूप में typedef क्योंकि typedef कीवर्ड का उपयोग करने पर अन्य भंडारण वर्गों में से कोई भी अनुमति नहीं है।

typedef महत्वपूर्ण हैं और इसे #define मैक्रो के साथ प्रतिस्थापित नहीं किया जाना चाहिए।

typedef int newType; 
newType *ptr;        // ptr is pointer to variable of type 'newType' aka int

तथापि,

#define int newType
newType *ptr;        // Even though macros are exact replacements to words, this doesn't result to a pointer to variable of type 'newType' aka int

ऑटो

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

चूंकि सभी वस्तुएं, वैश्विक दायरे में नहीं रहती हैं या static घोषित नहीं की जाती हैं, इसलिए परिभाषित होने पर डिफ़ॉल्ट रूप से स्वचालित भंडारण अवधि होती है, यह कीवर्ड ज्यादातर ऐतिहासिक रुचि है और इसका उपयोग नहीं किया जाना चाहिए:

int foo(void)
{
    /* An integer with automatic storage duration. */
    auto int i = 3;

    /* Same */
    int j = 5;

    return 0;
} /* The values of i and j are no longer able to be used. */

स्थिर

static भंडारण वर्ग विभिन्न उद्देश्यों को पूरा करता है, जो फ़ाइल में घोषणा के स्थान पर निर्भर करता है:

  1. पहचानकर्ता को केवल उस अनुवाद इकाई तक सीमित करने के लिए (गुंजाइश = फ़ाइल)।

    /* No other translation unit can use this variable. */
    static int i;
    
    /* Same; static is attached to the function type of f, not the return type int. */
    static int f(int n);
    
  2. किसी फ़ंक्शन के अगले कॉल के साथ उपयोग के लिए डेटा को बचाने के लिए (स्कोप = ब्लॉक):

     void foo()
     {
         static int a = 0; /* has static storage duration and its lifetime is the
                            * entire execution of the program; initialized to 0 on 
                            * first function call */ 
         int b = 0; /* b has block scope and has automatic storage duration and 
                     * only "exists" within function */
         
         a += 10;
         b += 10; 
    
         printf("static int a = %d, int b = %d\n", a, b);
     }
    
     int main(void)
     {
         int i;
         for (i = 0; i < 5; i++)
         {
             foo();
         }
    
         return 0;
     }
    

    यह कोड प्रिंट करता है:

     static int a = 10, int b = 10
     static int a = 20, int b = 10
     static int a = 30, int b = 10
     static int a = 40, int b = 10
     static int a = 50, int b = 10
    

स्टैटिक वैरिएबल कई अलग-अलग थ्रेड से बुलाए जाने पर भी अपना मूल्य बनाए रखते हैं।

C99
  1. एरे को निरूपित करने के लिए फंक्शन पैरामीटर्स में उपयोग किए जाने वाले तत्वों की एक निरंतर न्यूनतम संख्या और एक अशक्त पैरामीटर होने की उम्मीद है:

    /* a is expected to have at least 512 elements. */
    void printInts(int a[static 512])
    {
        size_t i;
        for (i = 0; i < 512; ++i)
            printf("%d\n", a[i]);
    }
    

    आवश्यक संख्या में आइटम (या यहां तक कि एक गैर-नल सूचक) आवश्यक रूप से संकलक द्वारा जांच नहीं की जाती है, और यदि आपके पास पर्याप्त तत्व नहीं हैं, तो संकलक को किसी भी तरह से आपको सूचित करने की आवश्यकता नहीं है। यदि कोई प्रोग्रामर 512 से कम तत्वों या अशक्त सूचक से गुजरता है, तो अपरिभाषित व्यवहार परिणाम है। चूंकि इसे लागू करना असंभव है, इसलिए इस तरह के फ़ंक्शन के लिए उस पैरामीटर के लिए एक मान पास करते समय अतिरिक्त देखभाल का उपयोग किया जाना चाहिए।

निर्वासन

एक ऐसी वस्तु या कार्य की घोषणा करने के लिए उपयोग किया जाता है जो कहीं और परिभाषित किया गया हो (और जिसमें बाहरी संबंध हो )। सामान्य तौर पर, इसका उपयोग किसी ऑब्जेक्ट या फ़ंक्शन को एक मॉड्यूल में उपयोग करने के लिए घोषित करने के लिए किया जाता है, वह ऐसा नहीं है जिसमें संबंधित ऑब्जेक्ट या फ़ंक्शन को परिभाषित किया जाता है:

/* file1.c */
int foo = 2;  /* Has external linkage since it is declared at file scope. */
/* file2.c */
#include <stdio.h>
int main(void)
{
    /* `extern` keyword refers to external definition of `foo`. */
    extern int foo;
    printf("%d\n", foo);
    return 0;
}
C99

C99 में inline कीवर्ड की शुरुआत के साथ चीजें थोड़ी दिलचस्प हो जाती हैं:

/* Should usually be place in a header file such that all users see the definition */
/* Hints to the compiler that the function `bar` might be inlined */
/* and suppresses the generation of an external symbol, unless stated otherwise. */
inline void bar(int drink)
{
    printf("You ordered drink no.%d\n", drink);
}

/* To be found in just one .c file.
   Creates an external function definition of `bar` for use by other files.
   The compiler is allowed to choose between the inline version and the external
   definition when `bar` is called. Without this line, `bar` would only be an inline
   function, and other files would not be able to call it. */
extern void bar(int);

रजिस्टर करें

संकलक को संकेत है कि किसी वस्तु तक पहुंच यथासंभव तेज होनी चाहिए। कंपाइलर वास्तव में संकेत का उपयोग करता है या नहीं, कार्यान्वयन-परिभाषित है; यह बस इसे auto बराबर मान सकता है।

एकमात्र गुण जो register साथ घोषित सभी वस्तुओं के लिए निश्चित रूप से अलग है, वह यह है कि उनके पते की गणना नहीं की जा सकती है। जिससे register कुछ अनुकूलन सुनिश्चित करने के लिए एक अच्छा उपकरण हो सकता है:

register size_t size = 467;

एक ऐसी वस्तु है जो कभी भी उर्फ नहीं हो सकती क्योंकि कोई भी कोड किसी अन्य फ़ंक्शन को अपना पता नहीं दे सकता है जहां इसे अप्रत्याशित रूप से बदला जा सकता है।

यह गुण भी एक सरणी से तात्पर्य है

register int array[5];

अपने पहले तत्व (यानी array बदलकर &array[0] ) के लिए एक सूचक में क्षय नहीं कर सकते। इसका मतलब यह है कि ऐसे एरे के तत्वों को एक्सेस नहीं किया जा सकता है और एरे को ही फंक्शन में पास नहीं किया जा सकता है।

वास्तव में, register स्टोरेज क्लास के साथ घोषित सरणी का एकमात्र कानूनी उपयोग sizeof ऑपरेटर है; किसी भी अन्य ऑपरेटर को सरणी के पहले तत्व के पते की आवश्यकता होगी। उस कारण से, सरणियों को आम तौर पर register कीवर्ड के साथ घोषित नहीं किया जाना चाहिए क्योंकि यह उन्हें संपूर्ण सरणी के आकार गणना के अलावा किसी अन्य चीज के लिए बेकार बनाता है, जिसे register कीवर्ड के बिना भी आसानी से किया जा सकता है।

register स्टोरेज क्लास उन वेरिएबल्स के लिए अधिक उपयुक्त है जो एक ब्लॉक के अंदर परिभाषित होते हैं और उच्च आवृत्ति के साथ एक्सेस किए जाते हैं। उदाहरण के लिए,

/* prints the sum of the first 5 integers*/
/* code assumed to be part of a function body*/ 
{ 
    register int k, sum;
    for(k = 1, sum = 0; k < 6; sum += k, k++);
        printf("\t%d\n",sum);
}
C11

_Alignof ऑपरेटर को register सरणियों के साथ उपयोग करने की भी अनुमति है।

_Thread_local

C11

यह बहु-थ्रेडिंग के साथ C11 में पेश किया गया एक नया स्टोरेज स्पेसिफिकेशन था। यह पहले के C मानकों में उपलब्ध नहीं है।

थ्रेड स्टोरेज अवधि को दर्शाता है। _Thread_local स्टोरेज _Thread_local साथ घोषित एक चर यह दर्शाता है कि ऑब्जेक्ट उस थ्रेड के लिए स्थानीय है और इसका जीवनकाल उस थ्रेड का संपूर्ण निष्पादन है जिसमें यह बनाया गया है। यह static या extern के साथ भी दिखाई दे सकता है।

#include <threads.h>
#include <stdio.h>
#define SIZE 5

int thread_func(void *id)
{
    /* thread local variable i. */
    static _Thread_local int i;

    /* Prints the ID passed from main() and the address of the i.
     * Running this program will print different addresses for i, showing
     * that they are all distinct objects. */
    printf("From thread:[%d], Address of i (thread local): %p\n", *(int*)id, (void*)&i);

    return 0;
}

int main(void)
{
    thrd_t id[SIZE];
    int arr[SIZE] = {1, 2, 3, 4, 5};

    /* create 5 threads. */
    for(int i = 0; i < SIZE; i++) {
        thrd_create(&id[i], thread_func, &arr[i]);
    }

    /* wait for threads to complete. */
    for(int i = 0; i < SIZE; i++) {
        thrd_join(id[i], NULL);
    }
}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow