2012-04-21 11 views
8

मैं एक वर्ष से भी कम समय के लिए सी ++ विकसित कर रहा हूं, लेकिन उस समय, मैंने कई लोगों को यह सुना है कि #define कितना भयानक है। अब, मुझे एहसास है कि यह संकलक के बजाय प्रीप्रोसेसर द्वारा व्याख्या किया गया है, और इस प्रकार, डीबग नहीं किया जा सकता है, लेकिन क्या यह वास्तव में बुरा है?सी ++ में "#define" का उपयोग करने के विकल्प? यह क्यों फहरा हुआ है?

यहाँ एक उदाहरण है (अपरीक्षित कोड, लेकिन आप सामान्य विचार प्राप्त):

#define VERSION "1.2" 

#include <string> 

class Foo { 
    public: 
    string getVersion() {return "The current version is "+VERSION;} 
}; 
  1. क्यों इस कोड को बुरा है?
  2. क्या #define का उपयोग करने का कोई विकल्प है?
+2

इस प्रश्न के विपरीत: [एक चर के बजाय #define का उपयोग क्यों करें] (http://stackoverflow.com/questions/6004963/why-use-define-instead-of-a-variable) –

+0

'परिभाषित करें ' एस मुश्किल संरचनाएं हैं और आसानी से गलत इस्तेमाल या दुर्व्यवहार किया जा सकता है। लेकिन 'गोटो' की तरह वे बहुत उपयोगी हो सकते हैं। – Anycorn

+1

[स्थिर कॉन्स बनाम #define] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/1637332/static-const-vs-define), विशेष रूप से यह [उत्तर] (http://stackoverflow.com/a/ 3835772/61574) पर्याप्त होना चाहिए। – Anonymous

उत्तर

8

यह कोड खराब क्यों है?

क्योंकि संस्करण ओवरराइट किया जा सकता है और संकलक आपको नहीं बताएगा।

क्या #define का उपयोग करने का कोई विकल्प है?

const char * VERSION = "1.2"; 

या

const std::string VERSION = "1.2"; 
+3

वास्तव में, जब आप मैक्रो को फिर से परिभाषित करते हैं तो संकलक * आपको * बताएगा। यहां तक ​​कि किसी भी चेतावनी विकल्प के बिना, जीसीसी आपको "चेतावनी:" फूड "के साथ चेतावनी देगा ... नोट: यह पिछली परिभाषा का स्थान है"। और यह केवल तभी करेगा जब मान अलग हैं, इसलिए आपको बेकार चेतावनियां नहीं मिलती हैं। –

+0

क्या किसी न किसी के पास '# परिभाषित' के समान दायरा है? मुझे लगता है कि एक '# परिभाषित' वास्तव में एक गुंजाइश नहीं है - यह कहीं भी जा सकता है। क्या एक कॉन्स कहीं भी इस्तेमाल किया जा सकता है? – Joel

+3

@ जोएल: 'परिभाषित' पर 'const x' के सबसे बड़े फायदों में से एक यह है कि यह स्कॉप्ड है। – Puppy

4

#define, स्वाभाविक बुरा नहीं है यह सिर्फ दुरुपयोग आसान है। एक संस्करण स्ट्रिंग की तरह कुछ के लिए यह ठीक काम करता है, हालांकि const char* बेहतर होगा, लेकिन कई प्रोग्रामर इसे इसके अलावा बहुत अधिक उपयोग करते हैं। उदाहरण के लिए टाइपेडफ के रूप में #define का उपयोग करना मूर्खतापूर्ण है, जब ज्यादातर मामलों में, टाइपिफ़ बेहतर होगा। तो #define कथन के साथ कुछ भी गलत नहीं है, और कुछ चीजें उनके बिना नहीं की जा सकती हैं। मामले के आधार पर उन्हें किसी मामले पर मूल्यांकन करना होगा। यदि आप प्रीप्रोसेसर का उपयोग किए बिना किसी समस्या को हल करने का कोई तरीका समझ सकते हैं, तो आपको यह करना चाहिए।

0

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

const char* VERSION = "1.2" 

हालांकि ऐसे मामलों में जहां यह असंभव है कि आप क्या पूर्वप्रक्रमक के बिना क्या करना चाहते करने के लिए देखते हैं:

#define Log(x) cout << #x << " = " << (x) << endl; 
+0

सी ++ में संकलन वास्तव में दो से अधिक पास लेता है। –

+0

मेरा तार्किक पास का मतलब है। –

+1

मुझे नहीं पता कि "तार्किक पास" से आपका क्या मतलब है। या बल्कि, मैं नहीं देखता कि यह स्वाभाविक रूप से असुरक्षित कैसे होगा। –

10

असली समस्या यह है कि परिभाषित करता है के द्वारा नियंत्रित किया जाता है है शेष भाषा (प्रीप्रोसेसर) से एक अलग उपकरण। नतीजतन, संकलक इसके बारे में नहीं जानता है, और कुछ गलत होने पर आपकी मदद नहीं कर सकता - जैसे प्रीप्रोसेसर नाम का पुन: उपयोग करना।

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

अब, कुछ देखभाल के साथ इस समस्या को कम किया जा सकता है (अगर पूरी तरह से समाप्त नहीं किया गया है)। लेकिन #define के अधिकांश उपयोगों के लिए वैसे भी बेहतर विकल्प हैं, इसलिए लागत/लाभ गणना कम हो जाती है: के लिए मामूली नुकसान कुछ भी लाभ। जब कोई लाभ नहीं मिलता है तो दोषपूर्ण सुविधा का उपयोग क्यों करें?

  1. एक निरंतर आवश्यकता है:

    तो यहाँ एक बहुत ही सरल चित्र है? एक निरंतर (परिभाषित नहीं)

  2. फ़ंक्शन की आवश्यकता है? एक फ़ंक्शन का उपयोग करें (परिभाषित नहीं)
  3. ऐसी किसी चीज़ की आवश्यकता है जिसे स्थिर या फ़ंक्शन का उपयोग करके मॉडलिंग नहीं किया जा सके? परिभाषित करें, लेकिन इसे ठीक से करें।

यह करना "ठीक से" अपने आप में एक कला है, लेकिन कुछ आसान दिशानिर्देश हैं:

  1. एक अनूठा नाम का प्रयोग करें। सभी राजधानियों, हमेशा एक अद्वितीय पुस्तकालय पहचानकर्ता द्वारा prefixed। max? बाहर। VERSION? बाहर। इसके बजाय, MY_COOL_LIBRARY_MAX और MY_COOL_LIBRARY_VERSION का उपयोग करें। उदाहरण के लिए, मैक्रोज़ के बड़े उपयोगकर्ता बूस्ट लाइब्रेरीज़, हमेशा BOOST_<LIBRARY_NAME>_ से शुरू होने वाले मैक्रोज़ का उपयोग करें।

  2. मूल्यांकन से सावधान रहें। असल में, मैक्रो में एक पैरामीटर केवल टेक्स्ट है जिसे प्रतिस्थापित किया जाता है। नतीजतन, #define MY_LIB_MULTIPLY(x) x * x टूटा हुआ है: इसे MY_LIB_MULTIPLY(2 + 5) के रूप में उपयोग किया जा सकता है, जिसके परिणामस्वरूप 2 + 5 * 2 + 5 हो सकता है। हम क्या चाहते थे नहीं। इसके खिलाफ सुरक्षा के लिए, हमेशा parenhesise सभी तर्कों का उपयोग (जब तक आप बिल्कुल जानते हैं कि आप क्या कर रहे हैं - spoiler: शायद आप नहीं करते; यहां तक ​​कि विशेषज्ञों को अक्सर यह गलत लगता है)।

    इस मैक्रो का सही संस्करण होगा:

    #define MY_LIB_MULTIPLY(x) ((x) * (x)) 
    

लेकिन अभी भी दोहराना के लिए मैक्रो बहुत गलत हो रही है, और, के तरीकों में से बहुत सारे हैं, संकलक आप मदद नहीं करेगा यहाँ।

2

मैं #define का उपयोग नहीं होगा एक निरंतर उपयोग static कीवर्ड या बेहतर अभी तक परिभाषित करने के लिए const int kMajorVer = 1; const int kMinorVer = 2; या const std::string kVersion = "1.2";

हर्ब Sutter एक उत्कृष्ट लेख यहां का ब्यौरा क्यों #define खराब है और कुछ उदाहरण है जहां सूचीबद्ध करता है वास्तव में एक ही चीज़ प्राप्त करने का कोई और तरीका नहीं: http://www.gotw.ca/gotw/032.htm

मूल रूप से कई चीजों के साथ इसकी तरह ठीक है जब आप इसे सही तरीके से उपयोग करते हैं लेकिन दुरुपयोग करना आसान है और मैक्रो त्रुटियां विशेष रूप से गुप्त हैं और डीबग करने के लिए एक बगजर हैं।

मैं व्यक्तिगत रूप से उन्हें सशर्त डीबग कोड और वेरिएंट डेटा प्रस्तुतियों के लिए उपयोग करता हूं, जो सटर लेख के अंत में विस्तृत है।

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