"स्थिर कास्ट" बनाम "# अल्पाइन" बनाम "एनम"


585

C में नीचे दिए गए कथनों में से कौन सा प्रयोग करना बेहतर है?

static const int var = 5;

या

#define var 5

या

enum { var = 5 };

35
दिलचस्प बात यह है कि यह लगभग बिल्कुल ही सवाल है जैसे स्टैकओवरफ्लो . com/ questions/ 1637332/static-const-vs-define । अंतर केवल इतना है कि यह प्रश्न C ++ के बारे में है, और यह एक C के बारे में है। चूंकि मेरा उत्तर C ++ विशिष्ट था, इसलिए मैं कहता हूं कि यह समान नहीं है, लेकिन अन्य असहमत हो सकते हैं।
TED

53
नहीं समान, निश्चित रूप से। ऐसे कई क्षेत्र हैं जहां C ++ संगतता कारणों से C सिंटैक्स की अनुमति देता है। उन मामलों में, "X करने का सबसे अच्छा तरीका क्या है" जैसे सवालों का C ++ में अलग-अलग जवाब होगा। उदाहरण के लिए वस्तु आरंभीकरण।
MSLters

इसके अलावा: stackoverflow.com/questions/1944041/…
jamesdlin

यह राय कैसे आधारित नहीं है? प्रत्येक का एक अलग उद्देश्य है
सैम हम्मामी

1
@RobertSsupportsMonicaCellio, हाँ। आभार के लिए धन्यवाद
विजय

जवाबों:


690

यह इस बात पर निर्भर करता है कि आपको किस मूल्य की आवश्यकता है। आपने (अब तक और सभी ने) तीसरा विकल्प छोड़ दिया:

  1. static const int var = 5;
  2. #define var 5
  3. enum { var = 5 };

नाम की पसंद के बारे में मुद्दों की अनदेखी, फिर:

  • यदि आपको एक पॉइंटर पास करने की आवश्यकता है, तो आपको (1) का उपयोग करना होगा।
  • चूंकि (2) स्पष्ट रूप से एक विकल्प है, आपको पॉइंटर्स को पास करने की आवश्यकता नहीं है।
  • दोनों (1) और (3) में डिबगर के प्रतीक तालिका में एक प्रतीक है - जो डिबगिंग को आसान बनाता है। यह अधिक संभावना है कि (2) का प्रतीक नहीं होगा, आपको आश्चर्य होता है कि यह क्या है।
  • (1) वैश्विक दायरे में सरणियों के लिए एक आयाम के रूप में इस्तेमाल नहीं किया जा सकता है; दोनों (2) और (3) कर सकते हैं।
  • (1) फ़ंक्शन दायरे में स्थिर सरणियों के लिए एक आयाम के रूप में इस्तेमाल नहीं किया जा सकता है; दोनों (2) और (3) कर सकते हैं।
  • C99 के तहत, इन सभी का उपयोग स्थानीय सरणियों के लिए किया जा सकता है। तकनीकी रूप से, (1) वीएलए (वैरिएबल-लेंथ एरे) का उपयोग किया जाएगा, हालांकि 'var' द्वारा संदर्भित आयाम निश्चित रूप से आकार 5 में तय किया जाएगा।
  • (1) स्विच स्टेटमेंट जैसी जगहों पर इस्तेमाल नहीं किया जा सकता है; दोनों (2) और (3) कर सकते हैं।
  • (1) स्थैतिक चर को इनिशियलाइज़ करने के लिए इस्तेमाल नहीं किया जा सकता है; दोनों (2) और (3) कर सकते हैं।
  • (2) कोड बदल सकते हैं जो आप नहीं बदलना चाहते थे क्योंकि यह प्रीप्रोसेसर द्वारा उपयोग किया जाता है; दोनों (1) और (3) की तरह अप्रत्याशित दुष्प्रभाव नहीं होंगे।
  • आप पता लगा सकते हैं कि क्या (2) प्रीप्रोसेसर में सेट किया गया है; न तो (1) और न ही (3) इसकी अनुमति देता है।

इसलिए, अधिकांश संदर्भों में, विकल्पों पर 'एनम' को प्राथमिकता दें। अन्यथा, पहली और आखिरी बुलेट पॉइंट्स को नियंत्रित करने वाले कारक होने की संभावना है - और अगर आपको दोनों को एक साथ संतुष्ट करने की आवश्यकता है, तो आपको कठिन सोचना होगा।

यदि आप C ++ के बारे में पूछ रहे थे, तो आप विकल्प (1) - स्टेटिक कास्ट - हर बार उपयोग करेंगे।


111
शानदार सूची! इसके साथ एक कमी यह enumहै कि वे int([C99] 6.7.2.2/3) के रूप में कार्यान्वित किए जाते हैं । एक #defineआपको अहस्ताक्षरित और लंबे Uऔर Lप्रत्यय के साथ निर्दिष्ट करता है , और constआपको एक प्रकार देता है। enumसामान्य प्रकार के रूपांतरणों के कारण समस्याएँ हो सकती हैं।
गॉथियर

37
(2) लोग हमेशा सुरक्षा के बारे में शिकायत करते हैं। मुझे समझ में नहीं आया कि क्यों न "#define var ((int) 5))" का उपयोग किया जाए और तूफान को आप एक परिभाषित के साथ टाइप सुरक्षा मिले।
इंगो ब्लैकमैन

6
@RedX: एक चिंता के लिए अंतरिक्ष के लिए आपको बहुत अजीब माहौल में रहना होगा। कहा, न तो enumऔर न ही #defineअतिरिक्त जगह का उपयोग करता है, प्रति से। मान ऑब्जेक्ट कोड में डेटा खंड या हीप या स्टैक पर संग्रहीत किए जाने के बजाय निर्देशों के भाग के रूप में दिखाई देगा। आपके पास कुछ स्थान आवंटित होगा static const int, लेकिन यदि आप कोई पता नहीं लगाते हैं तो कंपाइलर इसे अनुकूलित कर सकता है।
जोनाथन लेफ़्लर

15
enumS (और static const) के लिए एक और 'वोट' : उन्हें बदला नहीं जा सकता। a 'd defineहो सकता है #undefine, जहाँ a enumऔर static constदिए गए मान पर नियत हैं।
दैन टिमर

15
@QED: नहीं, धन्यवाद। एक साधारण स्थिरांक कोष्ठक के बाहर सुरक्षित है। या, मुझे दिखाओ कि कैसे एक कार्यक्रम जिसे वैध रूप से संकलित करने की उम्मीद की जा सकती है, कोष्ठक में 5 नहीं होने से बदल दिया जाएगा। यदि यह एक फ़ंक्शन-शैली मैक्रो के लिए तर्क था, या यदि अभिव्यक्ति में कोई भी ऑपरेटर थे, तो आप मुझे दोष देने के लिए सही होंगे, मैंने कोष्ठक को शामिल नहीं किया था। लेकिन यहाँ ऐसा नहीं है।
जोनाथन लेफलर

282

आम तौर पर बोलना:

static const

क्योंकि यह गुंजाइश का सम्मान करता है और टाइप-सेफ है।

केवल वही चेतावनी जो मैं देख सकता था: यदि आप चाहते हैं कि चर को संभवतः कमांड लाइन पर परिभाषित किया जाए। अभी भी एक विकल्प है:

#ifdef VAR // Very bad name, not long enough, too general, etc..
  static int const var = VAR;
#else
  static int const var = 5; // default value
#endif

जब भी संभव हो, मैक्रोज़ / एलिप्सिस के बजाय, एक प्रकार-सुरक्षित विकल्प का उपयोग करें।

यदि आप वास्तव में एक मैक्रो के साथ जाने के लिए आवश्यक हैं (उदाहरण के लिए, आप चाहते हैं __FILE__या __LINE__), तो आप अपने मैक्रो को बहुत सावधानी से नाम देंगे: इसके नामकरण सम्मेलन में बूस्ट परियोजना के नाम से शुरू होने वाले सभी ऊपरी मामलों की सिफारिश करता है (यहां BOOST_ ), पुस्तकालय से इनकार करते समय आप यह देखेंगे (आम तौर पर) विशेष क्षेत्र (पुस्तकालय) के नाम के बाद और फिर सार्थक नाम के साथ।

यह आम तौर पर लंबे नामों के लिए बनाता है :)


2
सहमत - #define के साथ भी कोड के प्रबंधन के बारे में पता नहीं है क्योंकि प्रीप्रोसेसर के रूप में कोडिंग का एक सामान्य खतरा है।
नीलडुरेंट

10
#Ifdef की तुलना में इसका # उपयोग बेहतर है, लेकिन अन्यथा मैं सहमत हूं। +1।
टिम पोस्ट

58
यह मानक C ++ इंजीलवाद है। नीचे दिए गए उत्तर में यह स्पष्ट करने के लिए बहुत स्पष्ट है कि वास्तव में विकल्प क्या हैं और क्या मतलब है। विशेष रूप से: मुझे बस "स्थिर कास्ट" के साथ एक समस्या थी। किसी ने हेडर फ़ाइल में लगभग 2000 "स्थिरांक" को परिभाषित करने के लिए इसका उपयोग किया था। तब यह हेडर फ़ाइल लगभग 100 ".c" और ".cpp" फ़ाइलों में शामिल थी। => 8 लाख "कब्ज" के लिए। महान। हाँ, मुझे पता है कि आप एक लिंकर का उपयोग अपरिचित कब्जों को हटाने के लिए कर सकते हैं, लेकिन फिर भी यह आपको छोड़ देता है जो "कॉन्स्ट" हैं जो संदर्भित हैं। अंतरिक्ष से बाहर भागना इस उत्तर में क्या गलत है।
इंगो ब्लैकमैन

2
@IngoBlackman: एक अच्छे संकलक के साथ, केवल staticजिनका पता लिया जाता है, उन्हें बने रहना चाहिए; और यदि पता लिया जाता है तो एक #defineया enum(कोई पता नहीं) का उपयोग नहीं किया जा सकता है ... इसलिए मैं वास्तव में यह देखने में विफल हूं कि क्या विकल्प का उपयोग किया जा सकता था। यदि आप "संकलन समय मूल्यांकन" के साथ दूर कर सकते हैं, तो आप extern constइसके बजाय देख सकते हैं ।
मथिउ एम।

15
@Tim पोस्ट: #ifअधिक बेहतर हो सकता है #ifdefबूलियन झंडे के लिए है, लेकिन इस मामले में यह यह असंभव को परिभाषित करने बनाना होगा varके रूप में 0कमांड लाइन से। तो इस मामले में, #ifdefअधिक समझ में आता है, जब तक के 0लिए एक कानूनी मूल्य है var
मार्टन

108

सी में, विशेष रूप से? C में सही उत्तर है: उपयोग #define(या, यदि उपयुक्त हो, enum)

हालांकि const, किसी वस्तु की टेढ़ी-मेढ़ी और टाइपिंग संपत्तियों का होना फायदेमंद है, जबकि constC में वास्तविकता में ऑब्जेक्ट्स (C ++ के विपरीत) सही स्थिरांक नहीं हैं और इसलिए आमतौर पर अधिकांश व्यावहारिक मामलों में बेकार होते हैं।

इसलिए, सी में चुनाव द्वारा निर्धारित किया जाना चाहिए कि आप अपने निरंतर उपयोग की योजना कैसे बनाते हैं। उदाहरण के लिए, आप किसी const intऑब्जेक्ट को caseलेबल के रूप में उपयोग नहीं कर सकते (जबकि मैक्रो काम करेगा)। आप किसी const intवस्तु को बिट-फील्ड चौड़ाई (जबकि मैक्रो काम करेंगे) के रूप में उपयोग नहीं कर सकते । C89 / 90 में आप constसरणी आकार निर्दिष्ट करने के लिए किसी ऑब्जेक्ट का उपयोग नहीं कर सकते (जबकि मैक्रो काम करेगा)। यहां तक ​​कि C99 में आप किसी constऑब्जेक्ट का उपयोग उस सरणी आकार को निर्दिष्ट करने के लिए नहीं कर सकते हैं जब आपको गैर- वीएलए सरणी की आवश्यकता होती है।

यदि यह आपके लिए महत्वपूर्ण है तो यह आपकी पसंद का निर्धारण करेगा। ज्यादातर समय, आपके पास #defineसी में उपयोग करने के अलावा कोई विकल्प नहीं होगा और दूसरे विकल्प को न भूलें, जो कि सी में सही स्थिरांक पैदा करता है enum

C ++ में constऑब्जेक्ट सही स्थिरांक होते हैं, इसलिए C ++ में constवेरिएंट को प्राथमिकता देना लगभग हमेशा बेहतर होता है ( staticC ++ में स्पष्ट की कोई आवश्यकता नहीं )।


6
"आप एक कास्ट इंट ऑब्जेक्ट का उपयोग केस लेबल के रूप में नहीं कर सकते हैं (जबकि एक मैक्रो काम करेगा)" ---> इस कथन के बारे में मैंने स्विच में सी में एक कॉन्स्टेंट इंट वेरिएबल का परीक्षण किया
जॉन

8
@ जॉन: ठीक है, आपको उस कोड को प्रदान करना होगा जिसे आपने परीक्षण किया था और विशिष्ट संकलक का नाम दिया था। const intकेस-लेबल में वस्तुओं का उपयोग करना सी भाषा के सभी संस्करणों में अवैध है। (बेशक, आपका कंपाइलर एक गैर-मानक C ++ के रूप में समर्थन करने के लिए स्वतंत्र है - भाषा विस्तार की तरह।)
AnT

11
"... और इसलिए अधिकांश व्यावहारिक मामलों में आमतौर पर बेकार होते हैं ।" मैं असहमत हूं। वे तब तक पूरी तरह से उपयोगी हैं जब तक आपको नाम को एक स्थिर अभिव्यक्ति के रूप में उपयोग करने की आवश्यकता नहीं है। सी में "स्थिर" शब्द का मतलब कुछ ऐसा है जिसका संकलन समय पर मूल्यांकन किया जा सकता है; constकेवल पढ़ने का मतलब है। const int r = rand();पूरी तरह से कानूनी है।
कीथ थॉम्पसन

सी ++ में, विशेष रूप से कंटेनर जैसे या के साथ constexprतुलना में उपयोग करना बेहतर है । conststlarraybitset
मयूख सरकार

1
@ आप को switch()कथन में परीक्षण करना होगा , caseएक में नहीं । मैंने अभी-अभी इस पर पकड़ लिया है got
हाय-एंजेल

32

के बीच का अंतर static constऔर #defineहै कि पूर्व का उपयोग करता है स्मृति और बाद में भंडारण के लिए स्मृति का उपयोग नहीं करता है। दूसरे, आप किसी पते का पास नहीं कर सकते, #defineजबकि आप किसी के पते को पास नहीं कर सकते static const। वास्तव में यह इस बात पर निर्भर करता है कि हम किस परिस्थिति में हैं, हमें इन दोनों में से किसी एक का चयन करना होगा। दोनों अलग-अलग परिस्थितियों में अपने सर्वश्रेष्ठ में हैं। कृपया यह न समझें कि एक दूसरे से बेहतर है ... :-)

अगर ऐसा होता, तो डेनिस रिची ने अकेले सबसे अच्छा रखा होता ... हाहाहा ... :-)


6
मेमोरी का उल्लेख करने के लिए +1, कुछ एम्बेडेड सिस्टम में अभी भी उतना नहीं है, हालांकि मैं शायद स्थैतिक अवरोधों का उपयोग करना शुरू कर दूंगा और यदि आवश्यक हो तो केवल #defines में बदल सकता हूं।
फ्लफीबेन

3
मैंने अभी इसका परीक्षण किया। दरअसल, const int #define या enum की तुलना में अतिरिक्त मेमोरी का उपयोग करता है। चूंकि हम एम्बेडेड सिस्टम प्रोग्राम करते हैं, इसलिए हम अतिरिक्त मेमोरी उपयोग को बर्दाश्त नहीं कर सकते हैं। तो, हम #define या enum का उपयोग करके वापस जाएंगे।
डेविड एंड्रिया

2
व्यावहारिक रूप से यह सच (अब) नहीं है कि constस्मृति का उपयोग करता है। GCC (4.5.3 और कुछ नए संस्करणों के साथ परीक्षण) const int-O3 का उपयोग करते समय आसानी से आपके कोड में एक प्रत्यक्ष शाब्दिक में अनुकूलन करता है । इसलिए यदि आप कम रैम एंबेडेड डेवलपमेंट (जैसे AVR) करते हैं तो यदि आप GCC या किसी अन्य संगत कंपाइलर का उपयोग करते हैं तो आप सुरक्षित रूप से C का उपयोग कर सकते हैं। मैंने इसका परीक्षण नहीं किया है, लेकिन क्लैंग से यही बात करने की उम्मीद है कि बी.डब्ल्यू.टी.
राफेल

19

सी #defineमें अधिक लोकप्रिय है। आप उदाहरण के लिए सरणी आकार घोषित करने के लिए उन मूल्यों का उपयोग कर सकते हैं:

#define MAXLEN 5

void foo(void) {
   int bar[MAXLEN];
}

एएनएसआई सी आपको static constइस संदर्भ में एस का उपयोग करने की अनुमति नहीं देता है जहां तक ​​मुझे पता है। C ++ में आपको इन मामलों में मैक्रोज़ से बचना चाहिए। तुम लिख सकते हो

const int maxlen = 5;

void foo() {
   int bar[maxlen];
}

और यहां तक ​​कि बाहर छोड़ दें staticक्योंकि आंतरिक संबंध constपहले से ही [सी ++ में] द्वारा निहित है ।


1
"आंतरिक जुड़ाव" से आपका क्या तात्पर्य है? मैं const int MY_CONSTANT = 5;एक फ़ाइल में हो सकता है और इसे extern const int MY_CONSTANT;दूसरे में एक्सेस कर सकता हूं । मैं constडिफ़ॉल्ट व्यवहार को बदलने के बारे में मानक (C99 कम से कम) में कोई जानकारी नहीं पा सका "6.2.2: 5 यदि किसी वस्तु के लिए एक पहचान for एर की घोषणा में and ले गुंजाइश है और कोई भंडारण-वर्ग की युक्ति, एर नहीं है, तो इसका लिंकेज बाहरी है"।
गौथियर

@ गौथियर: क्षमा करें, इसके बारे में। मुझे कहना चाहिए "सी + + भाषा में पहले से ही कास्ट द्वारा निहित है"। यह C ++ के लिए विशिष्ट है।
sellibitze

यह अच्छा @sellibitze रास्ते कुछ तर्क को देखने के लिए के बजाय टन की राय अगर कोई सच तर्क के लिए बोनस होगा, आप समझ गए!
पॉल

1
C99 के रूप में, आपका दूसरा स्निपेट कानूनी है। barएक वीएलए (चर लंबाई सरणी) है; संकलक कोड उत्पन्न करने की संभावना है जैसे कि इसकी लंबाई स्थिर थी।
कीथ थॉम्पसन

14

constC का एक और दोष यह है कि आप दूसरे को इनिशियलाइज़ करने में मूल्य का उपयोग नहीं कर सकते हैं const

static int const NUMBER_OF_FINGERS_PER_HAND = 5;
static int const NUMBER_OF_HANDS = 2;

// initializer element is not constant, this does not work.
static int const NUMBER_OF_FINGERS = NUMBER_OF_FINGERS_PER_HAND 
                                     * NUMBER_OF_HANDS;

यहां तक ​​कि यह एक कास्ट के साथ काम नहीं करता है क्योंकि कंपाइलर इसे एक स्थिर के रूप में नहीं देखता है:

static uint8_t const ARRAY_SIZE = 16;
static int8_t const lookup_table[ARRAY_SIZE] = {
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // ARRAY_SIZE not a constant!

मुझे constइन मामलों में टाइप करने में खुशी होगी , अन्यथा ...


5
खेल में थोड़ा देर हो गई, लेकिन यह सवाल एक और सवाल में आया। नीचे का पीछा करते हुए क्यों अपने static uint8_t const ARRAY_SIZE = 16;अचानक नहीं संकलन अब थोड़ा चुनौतीपूर्ण हो सकता है, खासकर जब #define ARRAY_SIZE 256हेडर के पेचीदा वेब में गहरी दस परतों को दफन किया जाता है। कि सभी कैप नाम ARRAY_SIZEपरेशानी के लिए पूछ रहे हैं। मैक्रोज़ के लिए ALL_CAPS आरक्षित करें, और ALL_CAPS फॉर्म में नहीं होने वाले मैक्रो को कभी भी परिभाषित न करें।
डेविड हैमेन

@ डेविड: ध्वनि सलाह, जिसका मैं पालन करूंगा।
गौथियर

1
4 साल बाद आपने मुझे यह बताने में बहुत समय दिया कि मैं "घोंसला" क्यों नहीं बना सकता const। यह और अधिक उत्कीर्ण किया जा सकता है!
प्लॉफ़

11

अगर आप इससे दूर हो सकते हैं, तो static constइसके कई फायदे हैं। यह सामान्य स्कोप सिद्धांतों का पालन करता है, डिबगर में दिखाई देता है, और आमतौर पर उन नियमों का पालन करता है जो चर मानते हैं।

हालांकि, कम से कम मूल सी मानक में, यह वास्तव में एक स्थिर नहीं है। यदि आप उपयोग करते हैं #define var 5, तो आप int foo[var];एक घोषणा के रूप में लिख सकते हैं , लेकिन आप ऐसा नहीं कर सकते (सिवाय इसके एक संकलक विस्तार के रूप में) static const int var = 5;यह C ++ में ऐसा नहीं है, जहां static constसंस्करण का उपयोग #defineसंस्करण कहीं भी किया जा सकता है, और मुझे विश्वास है कि C99 के मामले में भी यही है।

हालांकि, #defineलोअरकेस नाम के साथ एक स्थिरांक का नाम कभी न रखें । यह अनुवाद इकाई के अंत तक उस नाम के किसी भी संभावित उपयोग को ओवरराइड करेगा। मैक्रो स्थिरांक में होना चाहिए जो प्रभावी रूप से अपने स्वयं के नामस्थान है, जो परंपरागत रूप से सभी पूंजी पत्र हैं, शायद एक उपसर्ग के साथ।


6
दुर्भाग्य से, यह C99 के साथ ऐसा नहीं है। constC99 में अभी भी वास्तविक स्थिरांक नहीं है। आप constC99 में ए के साथ ऐरे आकार की घोषणा कर सकते हैं , लेकिन केवल इसलिए कि C99 वेरिएबल लेंथ एरे का समर्थन करता है। इस कारण से, यह केवल वही काम करेगा जहां वीएलएएएस की अनुमति है। उदाहरण के लिए, C99 में भी, आप अभी भी consta में सदस्य सरणी के आकार को घोषित करने के लिए उपयोग नहीं कर सकते हैं struct
एनटी

हालांकि यह सही है कि C99 आपको ऐसा नहीं करने देगा, GCC (4.5.3 के साथ परीक्षण) आपको पूरी तरह से सरणियों को एक const intआकार के साथ आरंभ करने देगा जैसे कि यह C ++ कास्ट या मैक्रो था। क्या आप मानक से GCC के इस विचलन पर निर्भर होना चाहते हैं, निश्चित रूप से आपकी पसंद है, मैं व्यक्तिगत रूप से इसके साथ जाऊंगा जब तक कि आप वास्तव में GCC या Clang की तुलना में किसी अन्य संकलक का उपयोग नहीं कर सकते, बाद में यहाँ एक ही सुविधा है (Clang के साथ परीक्षण) 3.7)।
राफेल

7

यह हमेशा #define के बजाय कास्ट का उपयोग करने के लिए बेहतर है। ऐसा इसलिए है क्योंकि कांसेप्ट को कंपाइलर और # डेफिन द्वारा प्रीप्रोसेसर द्वारा इलाज किया जाता है। यह ऐसा है जैसे #define खुद कोड (मोटे तौर पर बोलने) का हिस्सा नहीं है।

उदाहरण:

#define PI 3.1416

प्रतीकात्मक नाम पीआई को संकलक द्वारा कभी नहीं देखा जा सकता है; प्रीप्रोसेसर द्वारा इसे हटाया जा सकता है इससे पहले कि स्रोत कोड किसी कंपाइलर के पास पहुंच जाए। परिणामस्वरूप, PI नाम प्रतीक तालिका में दर्ज नहीं हो सकता है। यदि आप निरंतरता के उपयोग को शामिल करते हुए संकलन के दौरान एक त्रुटि प्राप्त करते हैं, तो यह भ्रामक हो सकता है, क्योंकि त्रुटि संदेश 3.1416 को संदर्भित कर सकता है, पीआई को नहीं। यदि PI को एक हेडर फ़ाइल में परिभाषित किया गया है जिसे आपने नहीं लिखा है, तो आपको पता नहीं चलेगा कि 3.1416 कहां से आया है।

यह समस्या एक प्रतीकात्मक डिबगर में भी फसल कर सकती है, क्योंकि, फिर से, आप जिस नाम से प्रोग्रामिंग कर रहे हैं वह प्रतीक तालिका में नहीं हो सकता है।

समाधान:

const double PI = 3.1416; //or static const...

6

#define var 5अगर आपको चीजें पसंद हैं तो आप परेशानी का कारण बनेंगे mystruct.var

उदाहरण के लिए,

struct mystruct {
    int var;
};

#define var 5

int main() {
    struct mystruct foo;
    foo.var = 1;
    return 0;
}

प्रीप्रोसेसर इसकी जगह लेगा और कोड संकलित नहीं करेगा। इस कारण से, पारंपरिक कोडिंग शैली का सुझाव है कि #defineसंघर्ष से बचने के लिए सभी निरंतर एस बड़े अक्षरों का उपयोग करते हैं।


6

मैंने एक अंतर प्रदर्शित करने के लिए त्वरित परीक्षण कार्यक्रम लिखा:

#include <stdio.h>

enum {ENUM_DEFINED=16};
enum {ENUM_DEFINED=32};

#define DEFINED_DEFINED 16
#define DEFINED_DEFINED 32

int main(int argc, char *argv[]) {

   printf("%d, %d\n", DEFINED_DEFINED, ENUM_DEFINED);

   return(0);
}

यह इन त्रुटियों और चेतावनियों के साथ संकलित है:

main.c:6:7: error: redefinition of enumerator 'ENUM_DEFINED'
enum {ENUM_DEFINED=32};
      ^
main.c:5:7: note: previous definition is here
enum {ENUM_DEFINED=16};
      ^
main.c:9:9: warning: 'DEFINED_DEFINED' macro redefined [-Wmacro-redefined]
#define DEFINED_DEFINED 32
        ^
main.c:8:9: note: previous definition is here
#define DEFINED_DEFINED 16
        ^

ध्यान दें कि एनम एक त्रुटि देता है जब परिभाषित एक चेतावनी देता है।


4

परिभाषा

const int const_value = 5;

हमेशा एक निरंतर मान को परिभाषित नहीं करता है। कुछ संकलक (उदाहरण के लिए 0.9.26 tcc ) सिर्फ "const_value" नाम से पहचानी गई स्मृति को आवंटित करते हैं। पहचानकर्ता "const_value" का उपयोग करके आप इस मेमोरी को संशोधित नहीं कर सकते। लेकिन आप फिर भी एक अन्य पहचानकर्ता का उपयोग करके मेमोरी को संशोधित कर सकते हैं:

const int const_value = 5;
int *mutable_value = (int*) &const_value;
*mutable_value = 3;
printf("%i", const_value); // The output may be 5 or 3, depending on the compiler.

इसका मतलब परिभाषा है

#define CONST_VALUE 5

एक निरंतर मूल्य को परिभाषित करने का एकमात्र तरीका है जिसे किसी भी तरह से संशोधित नहीं किया जा सकता है।


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

आप आंशिक रूप से सही हैं। मैंने विज़ुअल स्टूडियो 2012 के साथ कोड का परीक्षण किया और यह प्रिंट करता है 5। लेकिन कोई संशोधित नहीं कर सकता #defineक्योंकि यह प्रीप्रोसेसर मैक्रो है। यह बाइनरी प्रोग्राम में मौजूद नहीं है। यदि कोई उन सभी स्थानों को संशोधित करना चाहता CONST_VALUEथा, जहां एक का उपयोग किया जाता था, तो उसे एक-एक करके करना पड़ता था।
user2229691

3
@ यूगोरेन: मान लीजिए कि आप लिखते हैं #define CONST 5, फिर if (CONST == 5) { do_this(); } else { do_that(); }, और संकलक elseशाखा को समाप्त कर देता है । CONST6 में बदलने के लिए आप मशीन कोड को कैसे संपादित करने का प्रस्ताव रखते हैं ?
कीथ थॉम्पसन

@KeithThompson, मैंने कभी नहीं कहा कि यह आसानी से और मज़बूती से किया जा सकता है। बस #defineयह बुलेट-प्रूफ नहीं है।
बदसूरत

3
@ यूगोरेन: मेरा कहना है कि "मशीन कोड का संपादन" किसी के मान को बदलने के प्रभाव की नकल करने का एक समझदार तरीका नहीं है #define। स्रोत कोड और recompile को संपादित करने का एकमात्र वास्तविक तरीका यही है।
कीथ थॉम्पसन

4

हालाँकि यह सवाल पूर्णांक के बारे में था, यह ध्यान देने योग्य है कि #define और enums बेकार हैं यदि आपको एक स्थिर संरचना या स्ट्रिंग की आवश्यकता है। ये दोनों आमतौर पर संकेत के रूप में कार्य करने के लिए पारित किए जाते हैं। (स्ट्रिंग्स के साथ इसकी आवश्यकता है; संरचनाओं के साथ यह अधिक कुशल है।)

पूर्णांक के लिए के रूप में, यदि आप बहुत सीमित स्मृति के साथ एक एम्बेडेड वातावरण में हैं, तो आपको इस बारे में चिंता करने की आवश्यकता हो सकती है कि निरंतर कहाँ संग्रहीत है और इसे कैसे एक्सेस किया जाता है। कंपाइलर रन समय में दो कॉन्स्ट्स जोड़ सकता है, लेकिन कंपाइल टाइम में दो #Dfines जोड़ें। एक #define स्थिरांक को एक या एक से अधिक MOV [तत्काल] निर्देशों में परिवर्तित किया जा सकता है, जिसका अर्थ है कि स्थिरांक प्रोग्राम मेमोरी में प्रभावी रूप से संग्रहीत है। डेटा मेमोरी में एक कॉन्स्टेंट कॉन्स्टेंट को .const सेक्शन में स्टोर किया जाएगा। हार्वर्ड वास्तुकला के साथ सिस्टम में, प्रदर्शन और स्मृति उपयोग में अंतर हो सकते हैं, हालांकि वे संभवतः छोटे होंगे। वे आंतरिक छोरों के हार्ड-कोर अनुकूलन के लिए मायने रख सकते हैं।


3

मत सोचो कि "जो हमेशा सबसे अच्छा होता है" के लिए एक उत्तर है, लेकिन, जैसा कि मैथ्यू ने कहा

static const

सुरक्षित है #defineहालाँकि, मेरे सबसे बड़े पालतू जानवर के दृश्य स्टूडियो में डिबगिंग करते समय आप चर नहीं देख सकते हैं। यह एक त्रुटि देता है कि प्रतीक नहीं पाया जा सकता है।


1
"आप चर नहीं देख सकते हैं" ठीक है, यह चर नहीं है। यह नहीं बदलता है, आपको इसे देखने की आवश्यकता क्यों है? आप इसे हर जगह पा सकते हैं इसका उपयोग केवल लेबल की खोज करके किया जाता है। आपको एक #define देखने के लिए (या यहां तक ​​कि) की आवश्यकता क्यों होगी?
मार्शल इबैंक

3

संयोग से, एक विकल्प #define, जो उचित ढलान प्रदान करता है, लेकिन "वास्तविक" स्थिर की तरह व्यवहार करता है, "एनम" है। उदाहरण के लिए:

enum {number_ten = 10;}

कई मामलों में, एन्यूमरेटेड प्रकारों को परिभाषित करना और उन प्रकारों के चर बनाना उपयोगी है; यदि ऐसा किया जाता है, तो डिबगर अपने गणना नाम के अनुसार चर प्रदर्शित करने में सक्षम हो सकते हैं।

हालांकि ऐसा करने के साथ एक महत्वपूर्ण चेतावनी: सी ++ में, एन्यूमरेटेड प्रकार के पूर्णांक के साथ सीमित संगतता है। उदाहरण के लिए, डिफ़ॉल्ट रूप से, कोई उन पर अंकगणित नहीं कर सकता है। मुझे लगता है कि एनम के लिए एक जिज्ञासु डिफ़ॉल्ट व्यवहार होना चाहिए; हालांकि "सख्त एनम" प्रकार का होना अच्छा होता, सी + + आमतौर पर सी के साथ संगत होने की इच्छा को देखते हुए, मुझे लगता है कि "एनम" प्रकार का डिफ़ॉल्ट व्यवहार पूर्णांकों के साथ विनिमेय होना चाहिए।


1
सी में, एन्यूमरेशन स्थिरांक हमेशा प्रकार के होते हैं int, इसलिए "एनम हैक" का उपयोग अन्य पूर्णांक प्रकारों के साथ नहीं किया जा सकता है। (गणना प्रकार कुछ कार्यान्वयन-परिभाषित पूर्णांक प्रकार के साथ संगत है, जरूरी नहीं int, लेकिन इस मामले में वह प्रकार गुमनाम है जो कोई फर्क नहीं पड़ता।)
कीथ थॉम्पसन

@KeithThompson: जब से मैंने ऊपर लिखा है, मैंने पढ़ा है कि MISRA-C स्क्वॉक करेगा यदि कोई कंपाइलर intएक एन्यूमरेशन-टाइप किए गए वैरिएबल (जो कंपाइलर को करने की अनुमति देता है) के अलावा कोई अन्य टाइप करता है और कोई इस तरह के वैरिएबल को असाइन करने की कोशिश करता है अपने स्वयं के गणन का सदस्य। काश मानक समितियाँ निर्दिष्ट शब्दार्थ के साथ पूर्णांक प्रकारों की घोषणा के पोर्टेबल तरीके जोड़ देतीं। किसी भी मंच, charआकार की परवाह किए बिना , एक प्रकार की घोषणा करने में सक्षम होना चाहिए जो मॉड 65536 को लपेट देगा, भले ही कंपाइलर को बहुत सारे AND R0,#0xFFFFया समकक्ष निर्देश जोड़ना हो ।
सुपरकैट

आप उपयोग कर सकते हैं uint16_t, हालांकि यह एक गणन प्रकार नहीं है। उपयोगकर्ता को दिए गए एन्यूमरेशन प्रकार का प्रतिनिधित्व करने के लिए उपयोग किए जाने वाले पूर्णांक प्रकार को निर्दिष्ट करने के लिए अच्छा होगा, लेकिन आप व्यक्तिगत मूल्यों के typedefलिए uint16_tऔर उसी के साथ श्रृंखला की एक ही प्रभाव को प्राप्त कर सकते #defineहैं।
कीथ थॉम्पसन

1
@KeithThompson: मैं समझता हूं कि ऐतिहासिक कारणों से, हम इस तथ्य के साथ फंस गए हैं कि कुछ प्लेटफ़ॉर्म 2U < -1Lसही और दूसरों के रूप में गलत का मूल्यांकन करेंगे, और अब हम इस तथ्य के साथ फंस गए हैं कि कुछ प्लेटफॉर्म एक तुलना uint32_tऔर int32_tहस्ताक्षर किए गए के बीच लागू करेंगे और कुछ के रूप में अहस्ताक्षरित, लेकिन इसका मतलब यह नहीं है कि समिति सी को एक ऊर्ध्व-संगत उत्तराधिकारी को परिभाषित नहीं कर सकती है जिसमें ऐसे प्रकार शामिल हैं जिनके शब्दार्थ सभी संकलक पर संगत होंगे।
सुपरकैट

1

एक साधारण अंतर:

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

जैसा कि आप मान लेंगे, परिभाषित है कि स्थिर गति है।

उदाहरण के लिए, होना:

#define mymax 100

आप नहीं कर सकते printf("address of constant is %p",&mymax);

लेकिन होने

const int mymax_var=100

आप कर सकते हैं printf("address of constant is %p",&mymax_var);

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

हालांकि, स्थैतिक कास्ट के लिए हमारे पास एक चर है जो कहीं आवंटित किया गया है। Gcc के लिए, स्थैतिक कास्ट को प्रोग्राम के टेक्स्ट सेगमेंट में आवंटित किया जाता है।

ऊपर, मैं संदर्भ ऑपरेटर के बारे में बताना चाहता था ताकि संदर्भ को संदर्भ से बदल दें।


1
आपका उत्तर बहुत गलत है। यह C के बारे में है, आपका उत्तर C ++ से संबंधित है, जिसमें constक्वालिफायर के लिए बहुत अलग शब्दार्थ हैं । सी में एनम-कॉन्स्टेंट के अलावा सिम्बिका स्थिरांक नहीं हैं । A const intपरिवर्तनशील है। आप भाषा और विशिष्ट कार्यान्वयन को भी भ्रमित करते हैं। वस्तु को रखने की कोई आवश्यकता नहीं है। और यह gcc के लिए भी सही नहीं है: आम तौर पर यह अनुभाग constमें योग्य चर रखता है .rodata। लेकिन यह लक्ष्य प्लेटफॉर्म पर निर्भर करता है। और आपका मतलब है ऑपरेटर का पता &
इस साइट

0

हमने MBF16X पर उत्पादित कोडांतरक कोड को देखा ... दोनों वेरिएंट अंकगणित संचालन (उदाहरण के लिए ADD तत्काल) के लिए एक ही कोड में परिणाम करते हैं।

तो पुरानी शैली है, const intजबकि प्रकार की जाँच के लिए पसंद किया #defineजाता है। शायद यह संकलक-विशिष्ट है। तो अपने उत्पादित कोडांतरक कोड की जाँच करें।


-1

मुझे यकीन नहीं है कि अगर मैं सही हूं, लेकिन मेरी राय में #defineडी मूल्य कॉलिंग किसी भी अन्य सामान्य रूप से घोषित चर (या कास्ट वैल्यू) को कॉल करने की तुलना में बहुत तेज है। ऐसा इसलिए है क्योंकि जब प्रोग्राम चल रहा है और इसे कुछ सामान्य रूप से घोषित चर का उपयोग करने की आवश्यकता है, तो उस चर को प्राप्त करने के लिए स्मृति में सटीक स्थान पर कूदने की आवश्यकता है।

इसके विपरीत जब यह #defined मान का उपयोग करता है , तो प्रोग्राम को किसी भी आवंटित मेमोरी में कूदने की आवश्यकता नहीं है, यह सिर्फ मूल्य लेता है। यदि #define myValue 7और प्रोग्राम कॉलिंग myValue, यह ठीक वैसा ही व्यवहार करता है जैसे कि जब यह कॉल करता है 7

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.