C में स्थिर कार्य


172

C में फ़ंक्शन को स्थिर बनाने का क्या मतलब है?


7
@ नाइटक्रैकर: सी ++ में "तरीके" जैसी कोई चीज नहीं है। मुझे लगता है कि आप उद्देश्य-सी के साथ भ्रमित हैं।
बो पर्सन

1
नहीं, मैं अजगर के साथ भ्रमित हूँ। एक कक्षा के अंदर के कार्य को पायथन में एक विधि कहा जाता है।
orlp

जवाबों:


212

एक समारोह बनाना static अन्य अनुवाद इकाइयों से खाल यह है, जो मदद करता है प्रदान करते हैं कैप्सूलीकरण

helper_file.c

int f1(int);        /* prototype */
static int f2(int); /* prototype */

int f1(int foo) {
    return f2(foo); /* ok, f2 is in the same translation unit */
                    /* (basically same .c file) as f1         */
}

int f2(int foo) {
    return 42 + foo;
}

main.c :

int f1(int); /* prototype */
int f2(int); /* prototype */

int main(void) {
    f1(10); /* ok, f1 is visible to the linker */
    f2(12); /* nope, f2 is not visible to the linker */
    return 0;
}

8
क्या अनुवाद इकाई यहाँ उपयोग करने के लिए सही शब्दावली है? ऑब्जेक्ट फ़ाइल अधिक सटीक नहीं होगी? मैं जो समझता हूं, वह लिंकर से एक स्थिर फ़ंक्शन छिपा हुआ है और लिंकर ट्रांसलेशन इकाइयों पर काम नहीं करता है।
स्टीवन एकॉफ

2
मुझे यह भी कहना चाहिए था, कि मैं इसे लिंकर से छिपाए जाने के बारे में सोचना पसंद करता हूं; यह उस तरह से स्पष्ट लगता है।
स्टीवन एकहॉफ

1
इसलिए, आंतरिक फ़ंक्शन (कि हमें इसकी सी फ़ाइल के बाहर कॉल नहीं करना है), हमें इसे स्थिर फ़ंक्शन के रूप में रखना चाहिए, है ना? इसलिए, हम यह सुनिश्चित कर सकते हैं कि यह कहीं और कॉल न कर सके। धन्यवाद :)
hqt

1
आप इसे कैसे संकलित करते हैं? क्या आप उपयोग करते हैं #include <helper_file.c>? मुझे लगता है कि यह तब एक एकल अनुवाद इकाई बना देगा ...
1

2
@Atcold: जिस तरह से मैंने आपको कोड लिखा है वह कमांड लाइन में 2 स्रोत फ़ाइलों को शामिल करें, जैसे gcc -std=c99 -pedantic -Wall -Wextra main.c helper_file.c। फ़ंक्शंस के प्रोटोटाइप दोनों स्रोत फ़ाइलों (हेडर फ़ाइलों की कोई आवश्यकता नहीं) में मौजूद हैं। लिंकर कार्यों को हल करेगा।
पीएम

80

pmg encapsulation के बारे में हाजिर है; अन्य अनुवाद इकाइयों (या बल्कि, इसकी वजह से) से फ़ंक्शन को छुपाने से परे , कार्य करनाstatic से कंपाइलर अनुकूलन की उपस्थिति में प्रदर्शन लाभ भी मिल सकता है।

क्योंकि एक staticफ़ंक्शन को वर्तमान अनुवाद इकाई के बाहर कहीं से नहीं बुलाया जा सकता है (जब तक कि कोड अपने पते पर एक संकेतक नहीं लेता है), संकलक इसमें सभी कॉल बिंदुओं को नियंत्रित करता है।

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


9
... जब तक कि फ़ंक्शन का पता नहीं लिया जाता है।
कैफ़े

1
@ caf आपको फ़ंक्शन के पते से क्या मतलब है? मेरे लिए, फ़ंक्शन / चर वाले पते या संकलित समय पर असाइन किए गए पते की धारणा थोड़ा भ्रमित करने वाली है। क्या आप कृपया विस्तार से बता सकते हैं?
सईदहुसैन

2
@ क्रिप्टोकरोड: आपका प्रोग्राम मेमोरी में लोड होता है, इसलिए फ़ंक्शंस में मेमोरी लोकेशन भी होता है और एड्रेस प्राप्त किया जा सकता है। फ़ंक्शन पॉइंटर के साथ, आप उनमें से किसी को भी कॉल कर सकते हैं। यदि आप ऐसा करते हैं, तो यह उन अनुकूलन की सूची को कम कर देता है जो संकलक प्रदर्शन कर सकते हैं क्योंकि कोड को उसी स्थान पर बरकरार रहना चाहिए।

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

@caf यदि फ़ंक्शन का पता लिया जाता है, तो क्या कंपाइलर पता लगाएगा और इस उत्तर में वर्णित स्थिर फ़ंक्शन ऑप्टिमाइज़ेशन को बंद कर देगा (जैसे गैर-मानक ABI का उपयोग करना)? मुझे लगता है कि यह करना होगा।
सेवको

28

staticसी में कीवर्ड एक संकलित फ़ाइल (ग के रूप में ज के खिलाफ) तो समारोह केवल उस फ़ाइल में मौजूद है में प्रयोग किया जाता है।

आम तौर पर, जब आप एक फंक्शन बनाते हैं, तो कंपाइलर cruft जेनरेट करता है, लिंकर उस फंक्शन के लिए फंक्शन कॉल लिंक कर सकता है। यदि आप स्थैतिक कीवर्ड का उपयोग करते हैं, तो उसी फ़ाइल के भीतर अन्य फ़ंक्शन इस फ़ंक्शन को कॉल कर सकते हैं (क्योंकि यह लिंकर का सहारा लिए बिना किया जा सकता है), जबकि लिंकर के पास अन्य फ़ाइलों को फ़ंक्शन तक पहुंचने की कोई जानकारी नहीं है।


1
3Doub: "cruft" शब्द का उपयोग आपके द्वारा दिए गए क्रेडिट से अधिक सटीक है। प्रश्न के संदर्भ में, "cruft" यहां उपयोग करने के लिए सही शब्द है।
एरिक एरोनिटी

@ 3Doubloons मैं मानता हूं कि यह सरलीकृत है, लेकिन मुझे लगता है कि यह शुरुआती लोगों के लिए समझना इतना आसान बनाता है।
इंगो बुर्क

11

ऊपर के पदों को देखते हुए मैं एक बात और बताना चाहूंगा।

मान लीजिए कि हमारी मुख्य फ़ाइल ("main.c") इस तरह दिखती है:

#include "header.h"

int main(void) {
    FunctionInHeader();
}

अब तीन मामलों पर विचार करें:

  • केस 1: हमारी हेडर फाइल ("हैडर.एच") इस तरह दिखाई देती है:

    #include <stdio.h>
    
    static void FunctionInHeader();
    
    void FunctionInHeader() {
        printf("Calling function inside header\n");
    }

    फिर linux पर निम्न कमांड:

    gcc main.c header.h -o main

    सफल होंगे ! इसके बाद अगर कोई चलता है

    ./main

    आउटपुट होगा

    हेडर के अंदर कॉलिंग फंक्शन

    वह कौन सा है जो स्थिर फ़ंक्शन को प्रिंट करना चाहिए।

  • केस 2: हमारी हेडर फाइल ("हैडर.एच") इस तरह दिखती है:

    static void FunctionInHeader();     

    और हमारे पास एक और फ़ाइल "शीर्ष लेख" है, जो इस तरह दिखता है:

    #include <stdio.h>
    
    #include "header.h"
    
    void FunctionInHeader() {
        printf("Calling function inside header\n");
    }

    फिर निम्नलिखित कमांड

    gcc main.c header.h header.c -o main

    कोई त्रुटि देगा।

  • केस 3:

    केस 2 के समान, सिवाय इसके कि अब हमारी हेडर फाइल ("हैडर.एच") है:

    void FunctionInHeader(); // keyword static removed

    फिर 2 आदेश के रूप में एक ही आदेश सफल होगा, और आगे क्रियान्वयन ./main अपेक्षित परिणाम देगा।

तो इन परीक्षणों (एसर x86 मशीन, उबंटू ओएस पर निष्पादित) से मैंने एक धारणा बनाई

स्थिर कीवर्ड फ़ंक्शन को किसी अन्य * .c फ़ाइल में कहा जाता है, जहां इसे परिभाषित किया गया है, रोकता है।

अगर मैं ग़लत हूं तो मेरी गलती सुझाएं।


5

C प्रोग्रामर मॉड्यूल के अंदर चर और फ़ंक्शन घोषणाओं को छिपाने के लिए स्थिर विशेषता का उपयोग करते हैं, जितना कि आप जावा और C ++ में सार्वजनिक और निजी घोषणाओं का उपयोग करेंगे। सी स्रोत फ़ाइलें मॉड्यूल की भूमिका निभाती हैं। स्थैतिक विशेषता के साथ घोषित कोई भी वैश्विक चर या फ़ंक्शन उस मॉड्यूल के लिए निजी है। इसी तरह, स्थिर विशेषता के बिना घोषित कोई भी वैश्विक चर या फ़ंक्शन सार्वजनिक है और किसी अन्य मॉड्यूल द्वारा एक्सेस किया जा सकता है। जहाँ भी संभव हो, स्थैतिक विशेषता के साथ अपने चर और कार्यों की रक्षा करना अच्छा प्रोग्रामिंग अभ्यास है।


4

pmg का जवाब बहुत ही ठोस है। यदि आप जानना चाहते हैं कि वस्तु स्तर पर स्थैतिक घोषणाएँ कैसे काम करती हैं, तो यह नीचे दी गई जानकारी आपके लिए दिलचस्प हो सकती है। मैंने pmg द्वारा लिखे गए उसी कार्यक्रम का पुन: उपयोग किया और इसे .so (साझा ऑब्जेक्ट) फ़ाइल में संकलित किया

निम्नलिखित सामग्री कुछ मानव पठनीय में .so फ़ाइल को डंप करने के बाद हैं

0000000000000675 f1 : f1 फ़ंक्शन का पता

000000000000068c f2 : f2 (स्टेटिक) फ़ंक्शन का पता

फ़ंक्शन पते में अंतर पर ध्यान दें, इसका मतलब कुछ है। एक फ़ंक्शन के लिए जिसे अलग-अलग पते के साथ घोषित किया गया है, यह बहुत अच्छी तरह से संकेत दे सकता है कि एफ 2 बहुत दूर या ऑब्जेक्ट फ़ाइल के एक अलग सेगमेंट में रहता है।

लिंकर्स PLT (प्रोसीजर लिंकेज टेबल) और GOT (ग्लोबल ऑफसेट टेबल) नामक कुछ चीज़ों का इस्तेमाल करते हैं ताकि वे उन प्रतीकों को समझ सकें जिनसे उन्हें लिंक करने की पहुंच है।

अब के लिए सोचते हैं कि GOT और PLT जादुई रूप से सभी पतों को बांधते हैं और एक गतिशील अनुभाग इन सभी कार्यों की जानकारी रखता है जो लिंकर द्वारा दिखाई देते हैं।

.So फ़ाइल के डायनामिक सेक्शन को डंप करने के बाद हमें प्रविष्टियों का एक गुच्छा मिलता है लेकिन केवल f1 और f2 फ़ंक्शन में रुचि होती है।

डायनामिक सेक्शन में केवल f1 फ़ंक्शन के लिए पता 0000000000000675 है और f2 के लिए प्रविष्टि है !

संख्या: मान का आकार प्रकार बाइंड विज़ निडक्स नाम

 9: 0000000000000675    23 FUNC    GLOBAL DEFAULT   11 f1

और बस !। इस से यह स्पष्ट है कि लिंकर f2 फंक्शन को खोजने में असफल रहेगा क्योंकि यह इनसो फाइल के डायनामिक सेक्शन में नहीं है।


0

जब कुछ कार्यों तक पहुँच को प्रतिबंधित करने की आवश्यकता होती है, तो हम फ़ंक्शन को परिभाषित और घोषित करते समय स्थैतिक कीवर्ड का उपयोग करेंगे।

            /* file ab.c */ 
static void function1(void) 
{ 
  puts("function1 called"); 
} 
And store the following code in another file ab1.c

/* file ab1.c  */ 
int main(void) 
{ 
 function1();  
  getchar(); 
  return 0;   
} 
/* in this code, we'll get a "Undefined reference to function1".Because function 1 is declared static in file ab.c and can't be used in ab1.c */

यह उत्तर बहुत मददगार नहीं है।
fiscblog
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.