c - एक "स्थैतिक" समारोह क्या है?




function static (8)

प्रश्न सादे c कार्यों के बारे में था, सी ++ static विधियों, जैसा कि टिप्पणियों में स्पष्ट किया गया था।

ठीक है, मैं समझता हूं कि एक static चर क्या है, लेकिन static कार्य क्या है?

और ऐसा क्यों है कि यदि मैं कोई फ़ंक्शन घोषित करता हूं, तो void print_matrix कि void print_matrix ( ah बिना) और "ac" - मुझे "[email protected]@....) already defined in a.obj" , लेकिन BUT अगर मैं इसे static void print_matrix रूप में घोषित करता static void print_matrix तो यह संकलित करता है?

अद्यतन बस चीजों को साफ़ करने के लिए - मुझे पता है कि .c सहित बुरा है, जैसा कि आप में से कई ने बताया है। मैं इसे मुख्य रूप से मुख्य. main.c में स्थान को अस्थायी रूप से साफ़ करने के लिए करता हूं जब तक कि मेरे पास उन सभी कार्यों को उचित .h और .c फ़ाइलों में समूहित करने का बेहतर विचार न हो। बस एक अस्थायी, त्वरित समाधान।


"सी" कंपिलर में स्थिर फ़ंक्शन स्टैक पर इसके आंतरिक चर नहीं बनाएगा, इसलिए स्थैतिक फ़ंक्शन कॉल तेज़ है, और परिणामस्वरूप आप प्रारंभकर्ताओं का उपयोग नहीं कर सकते जैसे: char c = 'ए'।


एक स्थिर कार्य वह वर्ग है जिसे कक्षा के एक उदाहरण के विपरीत कक्षा में ही बुलाया जा सकता है।

उदाहरण के लिए एक गैर स्थैतिक होगा:

Person* tom = new Person();
tom->setName("Tom");

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

Person* tom = Person::createNewPerson();

निम्नलिखित सादे सी कार्यों के बारे में है - एक सी ++ कक्षा में संशोधक 'स्थिर' का एक और अर्थ है।

यदि आपके पास सिर्फ एक फ़ाइल है, तो यह संशोधक बिल्कुल कोई फर्क नहीं पड़ता है। अंतर कई परियोजनाओं के साथ बड़ी परियोजनाओं में आता है:

सी में, प्रत्येक "मॉड्यूल" (sample.c और sample.h का संयोजन) स्वतंत्र रूप से संकलित किया जाता है और बाद में उन संकलित ऑब्जेक्ट फ़ाइलों (sample.o) में से प्रत्येक को लिंकर द्वारा निष्पादन योग्य फ़ाइल में एक साथ जोड़ा जाता है।

आइए मान लें कि आपके पास अपनी मुख्य फ़ाइल में शामिल कई फाइलें हैं और उनमें से दो में एक फ़ंक्शन है जिसे केवल आंतरिक add(int a, b) आंतरिक add(int a, b) नामक सुविधा के लिए आंतरिक रूप से उपयोग किया जाता है - संकलक आसानी से उन दो मॉड्यूल के लिए ऑब्जेक्ट फाइलें बनाते हैं, लेकिन लिंकर एक त्रुटि फेंक देगा, क्योंकि यह एक ही नाम के साथ दो कार्यों को पाता है और यह नहीं जानता कि इसे किसके लिए उपयोग करना चाहिए (भले ही लिंक करने के लिए कुछ भी न हो, क्योंकि उन्हें कहीं और नहीं बल्कि इसकी अपनी फ़ाइल में उपयोग किया जाता है)।

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


पहला: आम तौर पर किसी अन्य फ़ाइल में .cpp फ़ाइल को शामिल करना एक बुरा विचार है - इससे इस तरह की समस्याएं आती हैं :-) सामान्य तरीका अलग संकलन इकाइयों को बनाना है, और शामिल फ़ाइल के लिए हेडर फ़ाइल जोड़ना है।

दूसरी बात यह है:

सी ++ में कुछ भ्रमित शब्दावली है - टिप्पणियों में इंगित किए जाने तक मुझे इसके बारे में पता नहीं था।

ए) static functions - सी से विरासत में मिला, और आप यहां किस बारे में बात कर रहे हैं। किसी भी कक्षा के बाहर। एक स्थिर कार्य का अर्थ है कि यह वर्तमान संकलन इकाई के बाहर दिखाई नहीं दे रहा है - इसलिए आपके मामले में a.obj की प्रतिलिपि है और आपके अन्य कोड की एक स्वतंत्र प्रति है। (कोड की कई प्रतियों के साथ अंतिम निष्पादन योग्य bloating)।

बी) static member function - ऑब्जेक्ट ओरिएंटेशन एक स्थैतिक विधि क्या है । एक कक्षा के अंदर रहता है। आप ऑब्जेक्ट इंस्टेंस के बजाए कक्षा के साथ इसे कॉल करते हैं।

ये दो अलग-अलग स्थिर कार्य परिभाषाएं पूरी तरह से अलग हैं। सावधान रहें - यहां ड्रेगन बनें।


सी + में स्थिर कार्यों और सी ++ में स्थिर सदस्य कार्यों के बीच एक बड़ा अंतर है। सी में, एक स्थिर फ़ंक्शन अपनी अनुवाद इकाई के बाहर दिखाई नहीं देता है, जो कि ऑब्जेक्ट फ़ाइल है जिसे संकलित किया जाता है। दूसरे शब्दों में, एक फ़ंक्शन स्थिर अपने दायरे को सीमित करता है। आप अपने * .c फ़ाइल में "निजी" होने के रूप में स्थिर कार्य के बारे में सोच सकते हैं (हालांकि यह सख्ती से सही नहीं है)।

सी ++ में, "स्थैतिक" वर्ग के सदस्यों के कार्यों और डेटा सदस्यों पर भी लागू हो सकता है। एक स्थिर डेटा सदस्य को "क्लास वेरिएबल" भी कहा जाता है, जबकि एक गैर स्थैतिक डेटा सदस्य "आवृत्ति चर" होता है। यह स्मॉलटाक शब्दावली है। इसका अर्थ यह है कि कक्षा के सभी ऑब्जेक्ट्स द्वारा साझा किए गए स्थिर डेटा सदस्य की केवल एक प्रति है, जबकि प्रत्येक ऑब्जेक्ट में एक गैर स्थैतिक डेटा सदस्य की अपनी प्रति होती है। तो एक स्थिर डेटा सदस्य अनिवार्य रूप से एक वैश्विक चर है, जो एक वर्ग का सदस्य है।

गैर स्थैतिक सदस्य कार्य कक्षा के सभी डेटा सदस्यों तक पहुंच सकते हैं: स्थैतिक और गैर स्थैतिक। स्टेटिक सदस्य फ़ंक्शन केवल स्थिर डेटा सदस्यों पर ही काम कर सकते हैं।

इसके बारे में सोचने का एक तरीका यह है कि सी ++ स्थिर डेटा सदस्यों और स्थिर सदस्य कार्यों में किसी भी वस्तु से संबंधित नहीं है, बल्कि पूरे वर्ग में है।


स्थिर कार्य का जवाब भाषा पर निर्भर करता है:

1) सीओ जैसे ओओपीएस के बिना भाषाओं में, इसका मतलब है कि फ़ंक्शन केवल उस फ़ाइल के भीतर पहुंच योग्य है जहां इसकी परिभाषा है।

2) ओओपीएस के साथ सी ++ जैसी भाषाओं में, इसका मतलब है कि फ़ंक्शन को बिना किसी उदाहरण के कक्षा में सीधे कॉल किया जा सकता है।


static कार्य वे कार्य होते हैं जो केवल उसी फ़ाइल में अन्य कार्यों के लिए दृश्यमान होते हैं (अधिक सटीक एक ही अनुवाद इकाई )।

संपादित करें : उन लोगों के लिए जिन्होंने विचार किया था कि प्रश्नों के लेखक का अर्थ 'वर्ग विधि' था: जैसा कि प्रश्न टैग किया गया है, C मतलब है कि वह एक सादा पुराना सी कार्य है। (सी ++ / जावा / ...) वर्ग विधियों के लिए, static अर्थ यह है कि इस विधि को कक्षा में ही बुलाया जा सकता है, उस कक्षा का कोई उदाहरण आवश्यक नहीं है।


न्यूनतम रननेबल बहु-फ़ाइल उदाहरण

एसी :

#include <stdio.h>

/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
https://.com/questions/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*void f() { puts("a f"); }*/

/* OK: only declared, not defined. Will use the one in main. */
void f(void);

/* OK: only visible to this file. */
static void sf() { puts("a sf"); }

void a() {
    f();
    sf();
}

मुख्य.c :

#include <stdio.h>

void a(void);        

void f() { puts("main f"); }

static void sf() { puts("main sf"); }

void m() {
    f();
    sf();
}

int main() {
    m();
    a();
    return 0;
}

संकलन :

gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o

आउटपुट :

main f
main sf
main f
a sf

व्याख्या

  • प्रत्येक फ़ाइल के लिए दो अलग-अलग फ़ंक्शन sf
  • एक साझा साझा समारोह f

सामान्य रूप से, गुंजाइश छोटा, बेहतर, इसलिए यदि आप कर सकते हैं तो हमेशा static कार्य घोषित करें।

सी प्रोग्रामिंग में, फ़ाइलों को अक्सर "वर्ग" का प्रतिनिधित्व करने के लिए उपयोग किया जाता है, और static कार्य कक्षा के "निजी" तरीकों का प्रतिनिधित्व करते हैं।

एक सामान्य सी पैटर्न this संरचना को पहले "विधि" तर्क के रूप में पास करना है, जो मूल रूप से सी ++ हुड के नीचे होता है।

इसके बारे में क्या मानक कहते हैं

सी 99 एन 1256 ड्राफ्ट 6.7.1 "स्टोरेज-क्लास विनिर्देशक" कहता है कि static एक "स्टोरेज-क्लास विनिर्देशक" है।

6.2.2 / 3 "पहचानकर्ताओं के internal linkage " कहते हैं static internal linkage तात्पर्य है:

यदि किसी ऑब्जेक्ट या फ़ंक्शन के लिए फ़ाइल स्कोप आइडेंटिफ़ायर की घोषणा में स्टोरेज-क्लास विनिर्देशक स्थिर होता है, तो पहचानकर्ता के पास आंतरिक संबंध होता है।

और 6.2.2 / 2 कहता है कि internal linkage हमारे उदाहरण में व्यवहार करता है:

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

जहां "अनुवाद इकाई" प्रीप्रोकैसिंग के बाद एक स्रोत फ़ाइल है।

ईएलएफ (लिनक्स) के लिए जीसीसी कैसे लागू करता है?

STB_LOCAL बाध्यकारी के साथ।

अगर हम संकलित करते हैं:

int f() { return 0; }
static int sf() { return 0; }

और प्रतीक तालिका को अलग से इकट्ठा करें:

readelf -s main.o

आउटपुट में शामिल हैं:

Num:    Value          Size Type    Bind   Vis      Ndx Name
  5: 000000000000000b    11 FUNC    LOCAL  DEFAULT    1 sf
  9: 0000000000000000    11 FUNC    GLOBAL DEFAULT    1 f

इसलिए बाध्यकारी उनके बीच एकमात्र महत्वपूर्ण अंतर है। Value सिर्फ .bss अनुभाग में उनका ऑफसेट है, इसलिए हम उम्मीद करते हैं कि यह अलग हो।

STB_LOCAL को ईएलएफ स्पेक पर http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html पर दस्तावेज किया गया है:

STB_LOCAL स्थानीय प्रतीकों को उनकी परिभाषा वाली ऑब्जेक्ट फ़ाइल के बाहर दिखाई नहीं दे रहा है। एक ही नाम के स्थानीय प्रतीक एक दूसरे के साथ हस्तक्षेप किए बिना कई फाइलों में मौजूद हो सकते हैं

जो static का प्रतिनिधित्व करने के लिए यह एक आदर्श विकल्प बनाता है।

स्थिर के बिना कार्य STB_GLOBAL , और spec कहता है:

जब लिंक संपादक कई स्थानापन्न ऑब्जेक्ट फ़ाइलों को जोड़ता है, तो यह उसी नाम के साथ STB_GLOBAL प्रतीकों की एकाधिक परिभाषाओं की अनुमति नहीं देता है।

जो एकाधिक गैर स्थैतिक परिभाषाओं पर लिंक त्रुटियों के अनुरूप है।

यदि हम -O3 साथ अनुकूलन को क्रैंक करते हैं, तो sf प्रतीक पूरी तरह से प्रतीक तालिका से हटा दिया जाता है: इसे किसी भी तरह से बाहर से उपयोग नहीं किया जा सकता है। TODO जब कोई ऑप्टिमाइज़ेशन नहीं होता है तो प्रतीक तालिका पर स्थैतिक फ़ंक्शंस क्यों रखें? क्या वे किसी भी चीज़ के लिए इस्तेमाल किया जा सकता है?

यह भी देखें

यह अपने आप का प्रयास करें

आपके साथ खेलने के लिए गिटहब पर उदाहरण





static