2009-10-28 17 views
159

vars का उपयोग #define प्रीप्रोसेसर से बेहतर करना बेहतर है? या शायद यह संदर्भ पर निर्भर करता है?स्थिर कॉन्स बनाम #define

प्रत्येक विधि के लिए फायदे/नुकसान क्या हैं?

+12

स्कॉट Meyers से बहुत अच्छी तरह से और अच्छी तरह से इस विषय को शामिल किया गया। "प्रभावी सी ++ तीसरा संस्करण" में उसका आइटम # 2। क्लास विशिष्ट स्थिरांक के लिए कक्षा के दायरे में दो विशेष मामलों (1) स्थिर कॉन्स को प्राथमिकता दी जाती है; (2) नामस्थान या अज्ञात स्कोप कॉन्स को #define पर प्राथमिकता दी जाती है। – Eric

+2

मैं Enums पसंद करते हैं। क्योंकि यह दोनों का संकर है। जब तक आप इसका एक चर बनाते हैं तब तक अंतरिक्ष पर कब्जा नहीं होता है। यदि आप बस स्थिर के रूप में उपयोग करना चाहते हैं, तो enum सबसे अच्छा विकल्प है। इसमें सी/सी ++ 11 एसडीडी में एक प्रकार की सुरक्षा है और यह भी एक पूर्ण स्थिर है। #define प्रकार असुरक्षित है, अगर कंपाइलर इसे अनुकूलित नहीं कर सकता है तो कॉन्स्ट स्पेस लेता है। – siddhusingh

+0

मेरा निर्णय है कि '# परिभाषा' या 'स्थिरांक' (स्ट्रिंग्स के लिए) का उपयोग करना है ** प्रारंभिक ** पहलू (इसे नीचे दिए गए उत्तरों के माध्यम से नहीं बताया गया है) द्वारा संचालित किया जाता है: यदि निरंतर विशिष्ट संकलन इकाई के भीतर निरंतर उपयोग किया जाता है, तो मैं 'स्थिर कॉन्स 'के साथ जाता हूं, अन्यथा मैं' # परिभाषित' का उपयोग करता हूं - स्थैतिक आदेश प्रारंभिकता से बचें ** फ़ियास्को ** https://isocpp.org/wiki/faq/ctors#static-init-order –

उत्तर

107

व्यक्तिगत रूप से, मैं प्रीप्रोसेसर से नफरत करता हूं, इसलिए मैं हमेशा कॉन्स के साथ जाऊंगा।

#define का मुख्य लाभ यह है कि इसे आपके प्रोग्राम में स्टोर करने की कोई स्मृति की आवश्यकता नहीं है, क्योंकि यह वास्तव में कुछ पाठ को एक शाब्दिक मूल्य के साथ बदल रहा है। इसका लाभ भी है कि इसमें कोई प्रकार नहीं है, इसलिए इसे चेतावनियां उत्पन्न किए बिना किसी भी पूर्णांक मान के लिए उपयोग किया जा सकता है।

"कॉन्स्ट" के लाभ यह है कि उन्हें स्कॉप्ड किया जा सकता है, और इन्हें उन परिस्थितियों में उपयोग किया जा सकता है जहां किसी ऑब्जेक्ट के पॉइंटर को पारित करने की आवश्यकता होती है।

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

namespace { 
    unsigned const seconds_per_minute = 60; 
}; 

int main (int argc; char *argv[]) { 
... 
} 
+0

यही वह है जिसे मैं जानना चाहता हूं। मेरी कंपनी में, रणनीति सभी स्ट्रिंग स्थिर को एक अलग फ़ाइल में # परिभाषित करने के लिए है। मैं सोच रहा था कि इसके बजाय कॉन्स वर्र्स का उपयोग करना बेहतर हो सकता है। धन्यवाद –

+7

* स्ट्रिंग * स्थिरांक विशेष रूप से उन लोगों में से एक हैं जिन्हें '# परिभाषित' होने से लाभ हो सकता है, कम से कम अगर उन्हें बड़े स्ट्रिंग स्थिरांक के लिए "बिल्डिंग ब्लॉक" के रूप में उपयोग किया जा सकता है।एक उदाहरण के लिए मेरा जवाब देखें। – AnT

+0

एक मामला मैंने नहीं सोचा था। आपके समय के लिए धन्यवाद। –

5

स्थिर स्थिरांक का उपयोग करना आपके कोड में किसी अन्य कॉन्स्ट चर का उपयोग करना है। इसका मतलब है कि जहां भी जानकारी आती है, वहां से पता लगाया जा सकता है, एक # परिभाषा के विपरीत जो पूर्व-संकलन प्रक्रिया में कोड में प्रतिस्थापित किया जाएगा।

आप इस प्रश्न के लिए सी ++ पूछे जाने वाले प्रश्न लाइट पर एक नज़र लेने के लिए चाहते हो सकता है: http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.7

1

कृपया यहाँ देखें: static const vs define

आम तौर पर एक स्थिरांक घोषणा (यह स्थिर होने की जरूरत नहीं होती)

36

यदि यह एक सी ++ सवाल है और यह एक विकल्प के रूप #define उल्लेख के लिए, तो इसके बारे में "वैश्विक" (अर्थात फ़ाइल गुंजाइश) स्थिरांक, वर्ग के सदस्यों के बारे में नहीं है। जब सी ++ static const में ऐसे स्थिरांक की बात आती है तो यह अनावश्यक है। सी ++ const में डिफ़ॉल्ट रूप से आंतरिक संबंध है और उन्हें static घोषित करने में कोई बात नहीं है। तो यह वास्तव में const बनाम #define है।

और अंत में, सी ++ const में बेहतर है। कम से कम क्योंकि इस तरह के स्थिरांक टाइप और स्कॉप्ड हैं। कुछ अपवादों के अलावा const से #define को प्राथमिकता देने के कोई कारण नहीं हैं।

स्ट्रिंग स्थिरांक, बीटीडब्ल्यू, इस तरह के अपवाद का एक उदाहरण है। #define घ स्ट्रिंग स्थिरांक के साथ एक संकलन समय C/C++ compilers के संयोजन सुविधा में

#define OUT_NAME "output" 
#define LOG_EXT ".log" 
#define TEXT_EXT ".txt" 

const char *const log_file_name = OUT_NAME LOG_EXT; 
const char *const text_file_name = OUT_NAME TEXT_EXT; 

पी एस के रूप में उपयोग कर सकते हैं दोबारा, अगर किसी ने static const को #define के विकल्प के रूप में उल्लेख किया है, तो आमतौर पर इसका मतलब है कि वे सी के बारे में बात कर रहे हैं, सी ++ के बारे में नहीं। मुझे आश्चर्य है कि इस सवाल का सही ढंग से टैग किया गया है या ...

4
  • एक स्थिर स्थिरांक लिखा गया (यह एक प्रकार है) और वैधता के लिए संकलक, परिभाषा आदि
  • एक #define redifined किया जा सकता द्वारा जाँच की जा सकती है जो कुछ भी अपरिभाषित

आमतौर पर आपको स्थिर कॉन्स पसंद करना चाहिए।इसका कोई नुकसान नहीं है। प्रप्रोसेसर का मुख्य रूप से सशर्त संकलन (और कभी-कभी वास्तव में गंदे चाल के लिए) के लिए उपयोग किया जाना चाहिए।

194

पेशेवरों और सब कुछ करने के लिए विपक्ष, उपयोग के आधार पर:

  • केवल पूर्णांक के लिए संभव

    • enums महत्व देता
    • ठीक से scoped/पहचानकर्ता संघर्ष अच्छी तरह से संभाला, विशेष रूप से सी ++ 11 enum कक्षाओं में मुद्दों जहां enum class X के लिए गणना X::
    • दृढ़ता से टाइप की गई है, लेकिन एक बड़े पर्याप्त हस्ताक्षरित या हस्ताक्षरित int आकार के लिए, जिस पर आपके पास कोई नियंत्रण नहीं है, के आधार पर असंबद्ध हैं। ++ 03 (यद्यपि आप एक फ़ील्ड निर्दिष्ट कर सकते हैं जिसमें enum पैक किया जाना चाहिए यदि enum संरचना/वर्ग/संघ का सदस्य है), जबकि सी ++ 11 int पर डिफ़ॉल्ट है लेकिन प्रोग्रामर
    • द्वारा स्पष्ट रूप से सेट किया जा सकता है पता नहीं ले सकता - वहां कोई नहीं है क्योंकि गणना मूल्य
    • मजबूत उपयोग संयम (जैसे उदाहरण के बिंदु पर प्रभावी रूप से इनलाइन प्रतिस्थापित किए जाते हैं। वृद्धि - template <typename T> void f(T t) { cout << ++t; } संकलित नहीं होगा, हालांकि आप अंतर्निहित कन्स्ट्रक्टर, कास्टिंग ऑपरेटर और उपयोगकर्ता परिभाषित ऑपरेटरों के साथ एक कक्षा में एक enum लपेट सकते हैं)
    • प्रत्येक निरंतर प्रकार को संलग्न enum से लिया गया, तो template <typename T> void f(T) पारित होने पर एक अलग तत्कालता प्राप्त करें विभिन्न enums से एक ही संख्यात्मक मूल्य, जिनमें से सभी किसी भी वास्तविक f(int) तत्काल से अलग हैं। प्रत्येक फ़ंक्शन का ऑब्जेक्ट कोड समान (पता ऑफसेट को अनदेखा कर सकता है) हो सकता है, लेकिन मैं एक कंपाइलर/लिंकर को अनावश्यक प्रतियों को खत्म करने की अपेक्षा नहीं करता, हालांकि यदि आप परवाह करते हैं तो आप अपने कंपाइलर/लिंकर को देख सकते हैं।
    • टाइपफॉफ़/decltype के साथ भी, संख्यात्मक_limits अर्थपूर्ण मूल्यों और संयोजनों के सेट में उपयोगी अंतर्दृष्टि प्रदान करने की उम्मीद नहीं कर सकते हैं (वास्तव में, "कानूनी" संयोजन स्रोत कोड में भी नहीं दिए गए हैं, enum { A = 1, B = 2 } पर विचार करें - A|B "कानूनी है ? "एक कार्यक्रम तर्क के नजरिए से)
    • enum के typename RTTI में विभिन्न स्थानों, संकलक संदेशों आदि में दिखाई दे सकते हैं - संभवतः, उपयोगी संभवतः कहानियो
    • आप अनुवाद इकाई वास्तव में मूल्य देखे बिना एक गणना उपयोग नहीं कर सकते , जिसका अर्थ है लाइब्रेरी एपीआई में एनम्स को हेडर में उजागर मूल्यों की आवश्यकता होती है, और make और अन्य टाइमस्टैम्प-आधारित पुनर्मूल्यांकन उपकरण क्लाइंट रीकंपिलेशन को ट्रिगर करते समय ट्रिगर करेंगे (खराब!)
  • consts
    • ठीक से scoped/पहचानकर्ता टकराव के मुद्दों को अच्छी तरह संभाला
    • मजबूत, एकल, उपयोगकर्ता द्वारा निर्दिष्ट प्रकार
      • आप "प्रकार" एक #define#define S std::string("abc") आला, लेकिन लगातार टाल करने के लिए कोशिश कर सकते हैं उपयोग के प्रत्येक बिंदु पर अलग temporaries के निर्माण दोहराया
    • एक परिभाषा नियम जटिलताओं
    • पता ले सकता है, उनके लिए कॉन्स संदर्भ बना सकता है आदि।
    • गैर const मूल्य है, जो काम करते हैं और प्रभाव को कम करता है, तो दो
    • मूल्य के बीच स्विच कार्यान्वयन फ़ाइल के अंदर रखा जा सकता है, परिवर्तन
    लेने के लिए एक स्थानीय recompile और सिर्फ ग्राहक लिंक की इजाजत दी के लिए सबसे समान
  • को परिभाषित करता है
    • "वैश्विक" गुंजाइश/अधिक परस्पर विरोधी प्रयोगों, जो मुश्किल से संकल्प संकलन मुद्दों और नहीं बल्कि समझदार त्रुटि संदेश से अप्रत्याशित रन-टाइम परिणाम उत्पन्न कर सकते होने का खतरा; उन्हें कम करके इस की आवश्यकता है:
      • , लंबे समय से अस्पष्ट और/या केंद्रीय रूप से समन्वित पहचानकर्ता और उन तक पहुंच का इस्तेमाल किया मिलान परोक्ष से लाभ नहीं कर सकते हैं/वर्तमान/कोएनिग-देखा-अप नाम स्थान, नाम स्थान उपनाम आदि
      • जबकि trumping बेस्ट-प्रैक्टिस टेम्पलेट पैरामीटर आइडेंटिफायर को सिंगल-कैरेक्टर अपरकेस अक्षरों (संभावित रूप से एक संख्या के बाद) होने की अनुमति देता है, लोअरकेस अक्षरों के बिना पहचानकर्ताओं का अन्य उपयोग पारंपरिक रूप से आरक्षित होता है और प्रीप्रोसेसर परिभाषित करता है (ओएस और सी/सी ++ लाइब्रेरी हेडर के बाहर)। एंटरप्राइज़ स्केल प्रीप्रोसेसर उपयोग के लिए यह प्रबंधनीय रहने के लिए महत्वपूर्ण है। तीसरे पक्ष के पुस्तकालयों का पालन करने की उम्मीद की जा सकती है। इसका अर्थ यह है कि मौजूदा कॉन्स या परिभाषाओं के लिए मौजूदा परिभाषाओं के माइग्रेशन में पूंजीकरण में बदलाव शामिल है, और इसलिए "सरल" पुन: संकलन के बजाय क्लाइंट स्रोत कोड में संपादन की आवश्यकता होती है। (व्यक्तिगत रूप से, मैं enumerations लेकिन consts नहीं का पहला अक्षर कैपिटल, तो मैं उन दोनों के बीच भी पलायन हिट होगी - हो सकता है समय है कि पुनर्विचार करना।)
    • अधिक संकलन समय आपरेशन संभव: स्ट्रिंग शाब्दिक संयोजन, stringification पहचानकर्ता
      • नकारात्मक पक्ष यह है कि #define X "x" दिया है और कुछ ग्राहक उपयोग "pre" X "post" आला में, संयोजन (उसके आकार ले रही है), अगर आप चाहते हैं या (एक क्रम-अस्थिर चर बनाने के लिए एक्स बल्कि एक निरंतर आप ग्राहक कोड में संपादन के लिए मजबूर की तुलना की जरूरत है केवल पुनर्मूल्यांकन के बजाए), जबकि यह संक्रमण const char* या const std::string से आसान है, क्योंकि वे पहले से ही उपयोगकर्ता को कॉन्सैट को शामिल करने के लिए मजबूर करते हैं एनेशन ऑपरेशंस (उदा। "pre" + X + "post"string के लिए)
    • sizeof सीधे पर उपयोग नहीं कर सकते एक अंकीय परिभाषित शाब्दिक
    • untyped (unsigned की तुलना में अगर जीसीसी चेतावनी दी है नहीं करता है)
    • कुछ संकलक/संयोजक/डिबगर चेन पेश नहीं हो सकता है पहचानकर्ता, तो आपको "जादू संख्या" (स्ट्रिंग्स, जो भी ...)
    • पता नहीं ले सकता
    • प्रतिस्थापित मूल्य संदर्भ में कानूनी (या अलग) नहीं होना चाहिए #define बनाया गया है, जैसा कि इसका मूल्यांकन किया गया है उपयोग के प्रत्येक बिंदु पर, इसलिए आप अभी तक घोषित वस्तुओं का संदर्भ नहीं दे सकते हैं, "कार्यान्वयन" पर निर्भर करते हैं जिसे पूर्व-शामिल नहीं किया जाना चाहिए, { 1, 2 } जैसे "स्थिरांक" बनाएं जिनका उपयोग सरणी प्रारंभ करने के लिए किया जा सकता है, या #define MICROSECONDS *1E-6 इत्यादि। (निश्चित रूप से इस की सिफारिश नहीं है!)
    • __FILE__ और __LINE__ की तरह कुछ विशेष चीजें मैक्रो प्रतिस्थापन
    • आप सशर्त कोड सहित के लिए #if बयान में अस्तित्व और मूल्य के लिए परीक्षण कर सकते हैं में शामिल किया जा सकता है (अधिक एक पोस्ट की तुलना में शक्तिशाली प्रीप्रोसेसिंग "अगर" प्रीप्रोसेसर द्वारा चुने जाने पर कोड को संकलित करने की आवश्यकता नहीं है), #undef -ine, redefine आदि का उपयोग करें।ग्राहक रखता जब ट्रिगर किया जाएगा,
        अनुवाद इकाई यह द्वारा प्रयोग किया जाता है, जो ग्राहक के उपयोग के लिए पुस्तकालयों में मैक्रो का मतलब है शीर्षक में होना चाहिए
      • तो make और अन्य टाइमस्टैम्प आधारित रखता उपकरण:
      • प्रतिस्थापित पाठ उजागर किया गया है वे (बुरा!) बदल रहे हैं
      • या कमांड लाइन है, जहां और भी अधिक ध्यान यकीन है कि क्लाइंट कोड बनाने के लिए आवश्यक है पर फिर कंपाइल है (उदाहरण के लिए Makefile या स्क्रिप्ट परिभाषा की आपूर्ति एक निर्भरता के रूप में सूचीबद्ध किया जाना चाहिए)

एक सामान्य नियम के रूप में, मैं const एस का उपयोग करता हूं और उन्हें सामान्य उपयोग के लिए सबसे अधिक पेशेवर विकल्प मानता हूं (हालांकि दूसरों के पास इस पुराने आलसी प्रोग्रामर से अपील की सादगी है)।

+17

+1: अपने सारांश – Chubsdad

+1

बहुत बढ़िया उत्तर की सराहना करें। एक छोटा सा नाइट: मैं कभी-कभी स्थानीय एनम का उपयोग करता हूं जो कोड की स्पष्टता के लिए शीर्षकों में नहीं हैं, जैसे छोटे राज्य मशीनों और ऐसे में। इसलिए उन्हें हर समय हेडर में होना जरूरी नहीं है। – kert

+0

@ कर्ट: ठोस बिंदु ... तदनुसार संपादित किया गया है। धन्यवाद। –

1

प्रीप्रोसेसर निर्देश #define का उपयोग करके स्थिरांक को परिभाषित करने की सिफारिश नहीं की जाती है, न केवल C++, बल्कि C में भी लागू करने की अनुशंसा नहीं की जाती है। इन स्थिरांकों में प्रकार नहीं होगा। यहां तक ​​कि C में भी स्थिरांक के लिए const का उपयोग करने का प्रस्ताव रखा गया था।

0

यदि आप कक्षा के सभी उदाहरणों के बीच साझा करने के लिए निरंतर परिभाषित कर रहे हैं, स्थिर स्थिरांक का उपयोग करें। यदि स्थिर प्रत्येक इंस्टेंस के लिए विशिष्ट है, तो केवल कॉन्स का उपयोग करें (लेकिन ध्यान दें कि कक्षा के सभी रचनाकारों को प्रारंभिक सूची में इस कॉन्स्ट सदस्य चर को प्रारंभ करना होगा)।

0

हमेशा प्रीप्रोसेसर जैसे कुछ अतिरिक्त उपकरणों पर भाषा सुविधाओं का उपयोग करना पसंद करते हैं।

ES.31: स्थिरांक या "कार्यों"

मैक्रो कीड़ों का एक प्रमुख स्रोत हैं के लिए मैक्रो का उपयोग न करें। मैक्रोज़ सामान्य स्कोप का पालन नहीं करते हैं और नियम टाइप करते हैं। मैक्रोज़ गुजरने के लिए सामान्य नियमों का पालन नहीं करते हैं। मैक्रोज़ यह सुनिश्चित करते हैं कि मानव पाठक कुछ अलग को संकलक देखता है। मैक्रोज़ उपकरण निर्माण जटिल।

C++ Core Guidelines

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