2009-04-23 6 views
40

मुझे पता है कि स्रोत फ़ाइल में स्थैतिक फ़ंक्शन घोषित होने पर इसका क्या अर्थ है। मैं कुछ कोड पढ़ रहा हूं, पाया कि हेडर फ़ाइलों में स्थिर फ़ंक्शन अन्य फ़ाइलों में शामिल किया जा सकता है।सी/सी ++: हेडर फ़ाइल में स्टेटिक फ़ंक्शन, इसका क्या अर्थ है?

उत्तर

53

क्या हेडर फ़ाइल में फ़ंक्शन परिभाषित किया गया है? ताकि वास्तविक कोड, समारोह में सीधे दिया जाता है इस तरह:

static int addTwo(int x) 
{ 
    return x + 2; 
} 

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

याद रखें कि #include: हेडर में मूल रूप से हेडर की सामग्री को चिपकाता है (और इसमें शामिल किसी भी अन्य शीर्षलेख) को सी फाइल में संकलक द्वारा देखा गया है। कंपाइलर कभी नहीं जानता कि एक विशेष फ़ंक्शन परिभाषा हेडर फ़ाइल से आई है।

अद्यतन: कई मामलों में, यह वास्तव में इसके बाद के संस्करण की तरह कुछ करने के लिए एक अच्छा विचार है, और मैं अपने जवाब बहुत काले और सफेद यह जो है एक तरह से चीजों को थोड़ा oversimplifying के बारे में लग रहा है एहसास। उदाहरण के लिए, कोड के लिए कि मॉडल (या बस का उपयोग करता है) intrinsic functions ऊपर की तरह व्यक्त किया जा सकता है, और एक स्पष्ट inline कीवर्ड भी साथ:

static inline int addTwo(int *x) 
{ 
    __add_two_superquickly(x); 
} 

यहाँ, __add_two_superquickly() समारोह एक काल्पनिक आंतरिक है, और हम पूरे चाहते के बाद से मूल रूप से एक ही निर्देश के लिए संकलित करने के लिए कार्य, हम वास्तव में इसे रेखांकित करना चाहते हैं। फिर भी, ऊपर एक मैक्रो का उपयोग करने से क्लीनर है।

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

+12

ठीक है, संकलक शायद छोटे कार्यों को रेखांकित करेगा। तो यह वास्तव में कम स्मृति का उपयोग कर सकता है, अगर समारोह पर्याप्त छोटा है।लेकिन मैं एक "इनलाइन" प्रीपेड करता हूं, इसलिए आपको अप्रयुक्त स्थिर कार्यों के बारे में चेतावनियां संकलित नहीं होती हैं। – quinmars

+0

@quinmars अच्छा बिंदु, मैंने संपादित किया है। बेहतर देर से, मुझे उम्मीद है। :) धन्यवाद। – unwind

+0

मुझे आश्चर्य है कि क्या लिंकर इसे अनुकूलित करेगा। यह b.obj पर addTwo को संदर्भित नहीं किया जा रहा है तो यह obj से परिभाषा को हटा देता है? यदि ऐसा है, तो ओवरहेड केवल (फ़ंक्शन का आकार) * है (विभिन्न ओबीजे फाइलों की संख्या जो इसका संदर्भ देती हैं)। अभी भी (समारोह का आकार) से बड़ा है, लेकिन बुरा नहीं है? – doorfly

10

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

7

जैसा कि अन्य कह रहे हैं, .c फ़ाइल में यह static फ़ंक्शन के समान ही है। ऐसा इसलिए है क्योंकि .c और .h फ़ाइलों के बीच कोई अर्थपूर्ण अंतर नहीं है; #include लाइनों (आमतौर पर नाम .h) नामक किसी भी और सभी फ़ाइलों की सामग्री के साथ वास्तव में कंप्रेसर (आमतौर पर .c नामित) की फ़ाइल के साथ बनाई गई फ़ाइल से बना संकलन इकाई होती है, जिसे प्रीप्रोसेसर द्वारा देखा जाता है।

यह सम्मेलन कि सी स्रोत .c नामक फ़ाइल में है और सार्वजनिक घोषणाएं .h नाम की फ़ाइलों में हैं, केवल एक सम्मेलन है। लेकिन यह आमतौर पर एक अच्छा है। उस सम्मेलन के तहत, .h फाइलों में दिखाई देने वाली एकमात्र चीजें घोषणाएं हैं ताकि आप आम तौर पर एक ही प्रोग्राम में परिभाषित परिभाषित करने से बचें।

इस विशेष मामले में, static कीवर्ड प्रतीक को मॉड्यूल के लिए निजी बनाता है, इसलिए एक बहु-परिभाषा संघर्ष समस्या का कारण बनने की प्रतीक्षा नहीं कर रहा है। तो उस अर्थ में, यह करना सुरक्षित है।लेकिन इस गारंटी की अनुपस्थिति में कि फ़ंक्शन को रेखांकित किया जाएगा, आप जोखिम लेते हैं कि #include पर होने वाले प्रत्येक मॉड्यूल में फ़ंक्शन को तुरंत चालू किया जाएगा, जो शीर्षलेख फ़ाइल कोड कोड में स्मृति की बर्बादी है।

मुझे निश्चित नहीं है कि आम तौर पर उपलब्ध सार्वजनिक हेडर में यह क्या करने का औचित्य साबित होगा।

.h फ़ाइल कोड उत्पन्न होता है और केवल एक ही .c फ़ाइल में शामिल है, तो मैं व्यक्तिगत रूप से फ़ाइल .h के अलावा कुछ पर जोर देना है कि यह वास्तव में एक सार्वजनिक हेडर बिल्कुल नहीं है नाम होगा। उदाहरण के लिए, एक उपयोगिता जो एक बाइनरी फ़ाइल को प्रारंभिक चर परिभाषा में परिवर्तित करती है, वह #include के माध्यम से उपयोग की जाने वाली फ़ाइल लिख सकती है और इसमें static परिवर्तनीय की घोषणा, और संभवतः static एक्सेसर या अन्य संबंधित उपयोगिता की परिभाषा भी हो सकती है कार्य करता है।

+1

शायद फ़ंक्शन में स्थैतिक वेरिएबल हैं जो कॉल (आंतरिक स्थिति) के बीच अपना मान संरक्षित करते हैं, और इस प्रकार प्रत्येक मॉड्यूल को कार्य के अपने क्लोन के द्वारा वर्रों की "अपनी निजी प्रति" मिलती है? –

+1

@ranReloaded, यह एक संभावना है। मैं व्यक्तिगत रूप से इससे बचूंगा क्योंकि यह स्पष्ट रूप से अनावश्यक कार्य निकायों को समाप्त करने के लिए "चालाकी से" इसे तोड़ने के लिए एक चतुर अनुकूलक (या कोड रखरखाव) के लिए बहुत अधिक अवसर प्रदान करेगा। साथ ही, यह प्रति अनुवाद इकाई आंतरिक स्थिति का एक सेट प्रदान करता है। यह सभी राज्य को एक स्पष्ट राज्य चर में रखने के लिए कम भ्रमित और कम नाजुक होगा, प्रत्येक कॉल में पारित किया जाएगा। – RBerteig

+0

हाँ, मैं उस 'डिजाइन' से सहमत नहीं हूं। मैं फ़ाइल-ग्लोबल स्टेटिक वर्र्स (सी) या क्लास के सदस्यों (सी ++) –

1

स्रोत फ़ाइल या हेडर फ़ाइल में परिभाषित करने में अर्थपूर्ण अंतर नहीं है, मूल रूप से दोनों का अर्थ स्थिर कीवर्ड का उपयोग करते समय सादे सी में समान होता है, आप इस दायरे को सीमित कर रहे हैं।

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

इसलिए, मेरा सुझाव है कि आपको केवल अपनी स्रोत फ़ाइल में अपना कार्यान्वयन होना चाहिए, न कि शीर्षलेख में।

+0

फ़ंक्शन में एक स्थिर स्थानीय चर शामिल होने पर एक मजबूत अर्थपूर्ण अंतर होता है। एक मामले में, स्थैतिक चर साझा किया जाएगा, दूसरे मामले में प्रत्येक संकलन इकाई के लिए कई अलग-अलग स्थिर चर होंगे। इसलिए कार्य व्यवहार पूरी तरह से अलग हो सकता है। – galinette

1

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

// header.h 

// interface part (for user?!) 
static inline float av(float a, float b); 

// implementation part (for developer) 
static inline float av(float a, float b) 
{ 
    return (a+b)/2.f; 
} 

एप्पल GLK ढांचे में वेक्टर गणित पुस्तकालय ऐसे constuction (जैसे GLKMatrix4.h) का उपयोग करता है: बहरहाल, यह आप एक हेडर फाइल में अलग इंटरफेस और कार्यान्वयन भागों को सम्मिलित करने के लिए एक आसान तरीका देता है।

2

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

इससे आपके निष्पादन योग्य आकार में वृद्धि हो सकती है, लेकिन यदि यह कार्य छोटा है तो यह नगण्य हो सकता है। लाभ यह है कि अधिकांश कंपाइलर फ़ंक्शन इनलाइन कर सकते हैं, जो कोड प्रदर्शन को बढ़ा सकता है।

लेकिन बड़ा ऐसा करने में अंतर हो सकता है जिसका उत्तर किसी भी उत्तर में नहीं किया गया था।

static int counter() 
{ 
    static int ctr = 0; 
    return ctr++; 
} 

के बजाय: अपने कार्य के रूप में एक स्थिर स्थानीय चर का उपयोग करता है

//header 
int counter(); 

//source 
int counter() 
{ 
    static int ctr = 0; 
    return ctr++; 
} 

फिर प्रत्येक स्रोत इस हेडर सहित फ़ाइल का अपना काउंटर होगा। यदि फ़ंक्शन को हेडर के अंदर घोषित किया गया है, और एक स्रोत फ़ाइल में परिभाषित किया गया है, तो काउंटर आपके पूरे कार्यक्रम में साझा किया जाएगा।

तो कह रहा है कि केवल अंतर ही प्रदर्शन होगा और कोड आकार गलत होगा।

संबंधित मुद्दे