2013-08-04 5 views
6

हाल ही में मैं सी ++ सर्वोत्तम प्रथाओं में सुधार करने के लिए स्कॉट मेयर्स द्वारा प्रभावी सी ++ द्वितीय संस्करण पढ़ रहा हूं। उनके सूचीबद्ध वस्तुओं में से एक प्री-प्रोसेसर मैक्रोज़ से बचने के लिए सी ++ प्रोग्रामर को प्रोत्साहित करता है और 'कंपाइलर को पसंद करता है'। वह कहता है कि #include और # ifdef/# ifndef से अलग सी ++ में मैक्रो के लगभग कोई कारण नहीं हैं।डीबग लॉग स्टेटमेंट के लिए प्री-प्रोसेसर मैक्रोज़ सी ++ में एक जगह है?

मैं अपने तर्क से सहमत हैं, के रूप में आप पूरा कर सकते हैं निम्नलिखित मैक्रो

#define min(a,b) ((a) < (b) ? (a) : (b)) 
निम्नलिखित सी के साथ

++ भाषा सुविधाओं

template<class T> 
inline const T & min(const T & a, const T & b) { 
    return a < b ? a : b; 
} 

जहां इनलाइन संकलक समारोह कॉल को निकालने का विकल्प देता है और इनलाइन कोड और टेम्पलेट डालें जो एकाधिक डेटा प्रकारों को संभाल सकता है जिनके पास ओवरलोड या निर्मित> ऑपरेटर है।

EDIT - यह टेम्पलेट घोषणा पूरी तरह से बताए गए मैक्रो से मेल नहीं खाती है यदि डेटा प्रकार ए और बी भिन्न होता है। उदाहरण के लिए पीट की टिप्पणी देखें।

हालांकि, मुझे पता है कि अगर डीबग लॉगिंग के लिए मैक्रो का उपयोग कर सी ++ में एक वैध इस्तेमाल होता है उत्सुक हूँ। यदि नीचे दी गई विधि अच्छी प्रथा नहीं है, तो क्या कोई वैकल्पिक तरीका सुझाएगा?

मैंने पिछले साल के लिए ऑब्जेक्टिव-सी में कोडिंग किया गया है और मेरी पसंदीदा 2 डी इंजन (Cocos2d) में से एक प्रवेश बयान बनाने के लिए एक मैक्रो का उपयोग किया।

/* 


* if COCOS2D_DEBUG is not defined, or if it is 0 then 
* all CCLOGXXX macros will be disabled 
* 
* if COCOS2D_DEBUG==1 then: 
*  CCLOG() will be enabled 
*  CCLOGERROR() will be enabled 
*  CCLOGINFO() will be disabled 
* 
* if COCOS2D_DEBUG==2 or higher then: 
*  CCLOG() will be enabled 
*  CCLOGERROR() will be enabled 
*  CCLOGINFO() will be enabled 
*/ 


#define __CCLOGWITHFUNCTION(s, ...) \ 
NSLog(@"%s : %@",__FUNCTION__,[NSString stringWithFormat:(s), ##__VA_ARGS__]) 

#define __CCLOG(s, ...) \ 
NSLog(@"%@",[NSString stringWithFormat:(s), ##__VA_ARGS__]) 


#if !defined(COCOS2D_DEBUG) || COCOS2D_DEBUG == 0 
#define CCLOG(...) do {} while (0) 
#define CCLOGWARN(...) do {} while (0) 
#define CCLOGINFO(...) do {} while (0) 

#elif COCOS2D_DEBUG == 1 
#define CCLOG(...) __CCLOG(__VA_ARGS__) 
#define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__) 
#define CCLOGINFO(...) do {} while (0) 

#elif COCOS2D_DEBUG > 1 
#define CCLOG(...) __CCLOG(__VA_ARGS__) 
#define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__) 
#define CCLOGINFO(...) __CCLOG(__VA_ARGS__) 
#endif // COCOS2D_DEBUG 

इस मैक्रो अविश्वसनीय उपयोगिता जो मैं अपने सी ++ प्रोग्राम में शामिल करने के लिए चाहते हैं के लिए प्रदान करता है: मैक्रो इस प्रकार है। एक उपयोगी लॉग बयान लेखन के रूप में सरल

CCLOG(@"Error in x due to y"); 

क्या और भी बेहतर है के रूप में, यह है कि COCOS2D_DEBUG 0 पर सेट है, तो इन बयानों दिन की रोशनी देख कभी नहीं है। लॉगिंग कथन का उपयोग किया जाना चाहिए या नहीं, यह देखने के लिए एक सशर्त कथन की जांच के लिए कोई ओवरहेड नहीं है। विकास से उत्पादन में संक्रमण करते समय यह सुविधाजनक है। सी ++ में एक ही प्रभाव को कैसे बना सकता है?

तो क्या इस प्रकार का मैक्रो एक सी ++ प्रोग्राम में है? क्या ऐसा करने का एक बेहतर, अधिक सी ++ तरीका है?

+4

मेरा मानना ​​है कि आपका "CCLOG()" मैक्रोज़ उपयोगी और उचित है, इसका एक उत्कृष्ट उदाहरण है। IMHO ... – paulsm4

+1

उम, कि 'min' टेम्पलेट फ़ंक्शन ** नहीं ** ** मैक्रो के समान काम करता है। इसे 'मिनट (1, 2 एल)' के साथ आज़माएं। –

+0

@PeteBecker मैं टेम्पलेट्स के साथ एक गुरु नहीं हूं, लेकिन क्या यह 1 इंट और 2 एल लंबे होने के कारण हो सकता है? प्रदान की गई टेम्पलेट घोषणा केवल उसी प्रकार की दो वस्तुओं के लिए फ़ंक्शन उत्पन्न करेगी। –

उत्तर

6

पहले, स्कॉट के बयान एक समय में किया गया था जब मैक्रो काफी overused थे, ऐतिहासिक कारणों से। हालांकि यह आमतौर पर सच है, ऐसे कुछ मामले हैं जहां मैक्रोज़ समझ में आता है। इनमें से लॉगिंग है, क्योंकि केवल एक मैक्रो स्वचालित रूप से __FILE__ और __LINE__ डाल सकता है। इसके अलावा, केवल एक मैक्रो बिल्कुल कुछ भी हल नहीं कर सकता (हालांकि मेरे अनुभव के आधार पर, यह एक बड़ा सौदा नहीं है)।

आपके जैसे मैक्रोज़ सी ++ में अक्सर नहीं होते हैं।वहाँ प्रवेश के लिए दो सामान्य वेरिएंट हैं:

#define LOG(message) ... << message ... 

जो फार्म " x = " << x में संदेशों की अनुमति देता है, और पूरी तरह से मैक्रो को पुनर्परिभाषित द्वारा दबा दिया जा सकता है, और

#define LOG() logFile(__FILE__, __LINE__) 

जहां logFile एक के लिए एक आवरण रिटर्न std::ostream, जो को परिभाषित करता है operator<<, और के रूप में ऐसी बातों के लिए परमिट:

LOG() << "x = " << x; 

इस तरह से किया गया, LOG() के दाईं ओर सभी अभिव्यक्तियों का मूल्यांकन किया जाएगा, लेकिन सही ढंग से किया जाएगा, कोई प्रारूपण तब तक किया जाएगा जब तक लॉग सक्रिय न हो।

2

मैक्रोज़ का उपयोग करने के लिए "सही" चीजें हैं और मैक्रोज़ के खराब उपयोग हैं। मैक्रोज़ का उपयोग जहां कार्य करता है एक बुरा विचार है। मैक्रोज़ का उपयोग करना जहां कार्य एक ही काम नहीं करते हैं मेरी पुस्तक में पूरी तरह से अच्छा है।

मैं अक्सर इस तरह निर्माणों का उपयोग करें:

enum E 
{ 
    a, 
    b, 
    c, 
    d 
}; 

struct enum_string 
{ 
    E v; 
    const char *str; 
}; 

#define TO_STR(x) { x, #x } 

enum_string enum_to_str[] = 
{ 
    TO_STR(a), 
    TO_STR(b), 
    TO_STR(c), 
    TO_STR(d), 
    }; 

काफी सामान दोहरा का एक सा बचाता है ...

:

#defien my_assert(x) do { if (!x) assert_failed(x, #x, __FILE__, __LINE__); } while(0) 

template<typename T> 
void assert_failed(T x, const char *x_str, const char *file, int line) 
{ 
    std::cerr << "Assertion failed: " << x_str << "(" << x << ") at " << file << ":" << line << std::endl; 
    std::terminate(); 
} 

एक और चाल stringizing "ऑपरेटर" का उपयोग कर कुछ इस तरह है

तो, हाँ, यह कुछ मामलों में उपयोगी है।

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