न्यूनतम रननीय बहु-फ़ाइल गुंजाइश उदाहरण
यहाँ मैं वर्णन करता हूँ कि कैसे static
करता कई फ़ाइलों में फ़ंक्शन परिभाषाओं के दायरे को प्रभावित करता है।
एसी
#include <stdio.h>
/* Undefined behavior: already defined in main.
* Binutils 2.24 gives an error and refuses to link.
* /programming/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();
}
main.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
आउटपुट:
main f
main sf
main f
a sf
व्याख्या
- दो अलग-अलग कार्य हैं
sf
, प्रत्येक फ़ाइल के लिए एक
- एक एकल साझा समारोह है
f
हमेशा की तरह, छोटा दायरा, बेहतर, इसलिए हमेशा फ़ंक्शन घोषित करें static
यदि आप कर सकते हैं।
सी प्रोग्रामिंग में, फ़ाइलों को अक्सर "कक्षाएं" का प्रतिनिधित्व करने के लिए उपयोग किया जाता है, और static
फ़ंक्शन "निजी" तरीकों का प्रतिनिधित्व करते हैं।
पास करने के लिए एक सामान्य सी पैटर्न है this
पहले "विधि" तर्क के रूप में संरचना , जो मूल रूप से हुड के नीचे सी ++ करता है।
इसके बारे में क्या मानक कहते हैं
C99 N1256 ड्राफ्ट 6.7.1 "स्टोरेज-क्लास स्पेसियर्स " का कहना है कि static
यह "स्टोरेज-क्लास स्पेसियर " है।
6.2.2 / 3 "पहचानकर्ताओं के लिंक" का 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.syminab.html पर ELF कल्पना पर प्रलेखित है :
STB_LOCAL स्थानीय चिह्न उनकी परिभाषा वाली ऑब्जेक्ट फ़ाइल के बाहर दिखाई नहीं देते हैं। एक ही नाम के स्थानीय प्रतीक एक दूसरे के साथ हस्तक्षेप किए बिना कई फाइलों में मौजूद हो सकते हैं
जो इसका प्रतिनिधित्व करने के लिए एक आदर्श विकल्प है static
।
स्थिर के बिना कार्य हैं STB_GLOBAL
, और युक्ति कहती है:
जब लिंक एडिटर कई रिलेक्वेसेबल ऑब्जेक्ट फ़ाइलों को जोड़ता है, तो यह एक ही नाम के साथ STB_GLOBAL प्रतीकों की कई परिभाषाओं की अनुमति नहीं देता है।
जो कई गैर स्थिर परिभाषाओं पर लिंक त्रुटियों के साथ सुसंगत है।
यदि हम अनुकूलन को क्रैंक करते हैं -O3
, तो sf
प्रतीक पूरी तरह से प्रतीक तालिका से हटा दिया जाता है: इसका उपयोग किसी भी तरह से बाहर से नहीं किया जा सकता है। TODO जब अनुकूलन नहीं है तो प्रतीक तालिका पर स्थिर कार्य क्यों रखें? क्या उन्हें किसी भी चीज के लिए इस्तेमाल किया जा सकता है?
यह सभी देखें
C ++ अनाम नामस्थान
C ++ में, आप स्थैतिक के बजाय अनाम नामस्थान का उपयोग करना चाह सकते हैं, जो एक समान प्रभाव प्राप्त करता है, लेकिन आगे प्रकार की परिभाषाएँ छिपाता है: / अनाम नाम स्थान बनाम स्थिर कार्य