न्यूनतम रननीय बहु-फ़ाइल गुंजाइश उदाहरण
यहाँ मैं वर्णन करता हूँ कि कैसे 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_LOCALhttp://www.sco.com/developers/gabi/2003-12-17/ch4.syminab.html पर ELF कल्पना पर प्रलेखित है :
STB_LOCAL स्थानीय चिह्न उनकी परिभाषा वाली ऑब्जेक्ट फ़ाइल के बाहर दिखाई नहीं देते हैं। एक ही नाम के स्थानीय प्रतीक एक दूसरे के साथ हस्तक्षेप किए बिना कई फाइलों में मौजूद हो सकते हैं
जो इसका प्रतिनिधित्व करने के लिए एक आदर्श विकल्प है static।
स्थिर के बिना कार्य हैं STB_GLOBAL, और युक्ति कहती है:
जब लिंक एडिटर कई रिलेक्वेसेबल ऑब्जेक्ट फ़ाइलों को जोड़ता है, तो यह एक ही नाम के साथ STB_GLOBAL प्रतीकों की कई परिभाषाओं की अनुमति नहीं देता है।
जो कई गैर स्थिर परिभाषाओं पर लिंक त्रुटियों के साथ सुसंगत है।
यदि हम अनुकूलन को क्रैंक करते हैं -O3, तो sfप्रतीक पूरी तरह से प्रतीक तालिका से हटा दिया जाता है: इसका उपयोग किसी भी तरह से बाहर से नहीं किया जा सकता है। TODO जब अनुकूलन नहीं है तो प्रतीक तालिका पर स्थिर कार्य क्यों रखें? क्या उन्हें किसी भी चीज के लिए इस्तेमाल किया जा सकता है?
यह सभी देखें
C ++ अनाम नामस्थान
C ++ में, आप स्थैतिक के बजाय अनाम नामस्थान का उपयोग करना चाह सकते हैं, जो एक समान प्रभाव प्राप्त करता है, लेकिन आगे प्रकार की परिभाषाएँ छिपाता है: / अनाम नाम स्थान बनाम स्थिर कार्य