सी ++ मैक्रो कब फायदेमंद हैं? [बन्द है]


177

सी पूर्वप्रक्रमक उचित डर था और सी ++ समुदाय द्वारा त्याग दिया है। इन-लाइन किए गए फ़ंक्शंस, कॉस्ट और टेम्प्लेट आम तौर पर एक सुरक्षित और बेहतर विकल्प होते हैं #define

निम्नलिखित मैक्रो:

#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)  

किसी भी तरह से सुरक्षित प्रकार से बेहतर नहीं है:

inline bool succeeded(int hr) { return hr >= 0; }

लेकिन मैक्रोज़ के पास अपनी जगह है, कृपया मैक्रो के लिए आपके द्वारा उपयोग किए जाने वाले उपयोगों को सूचीबद्ध करें जो आप प्रीप्रोसेसर के बिना नहीं कर सकते हैं

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


मैंने एक बार मैक्रोज़ से भरा एक सी ++ आवेदन लिया था जिसे बनाने में 45 मिनट लगे, मैक्रोज़ को इनलाइन कार्यों से बदल दिया, और बिल्ड को 15 मिनट से भी कम समय तक मिला।
एंडियन


यह धागा ऐसे संदर्भों के बारे में है जिसमें मैक्रोज़ फायदेमंद होते हैं, न कि ऐसे संदर्भ जिनमें वे उप-समरूप होते हैं।
अंडरस्कोर_ड

जवाबों:


123

डिबग कार्यों के लिए रैपर के रूप में, स्वचालित रूप से तरह बातें पारित करने के लिए __FILE__, __LINE__, आदि:

#ifdef ( DEBUG )
#define M_DebugLog( msg )  std::cout << __FILE__ << ":" << __LINE__ << ": " << msg
#else
#define M_DebugLog( msg )
#endif

14
असल में, मूल स्निपेट: << FILE ":" << ठीक है, FILE एक स्ट्रिंग स्थिरांक उत्पन्न करता है, जिसे पूर्व-प्रोसेसर द्वारा एकल स्ट्रिंग में ":" के साथ समतल किया जाएगा।
फ्रैंक स्ज़िकगेटा

12
यह केवल क्योंकि पूर्वप्रक्रमक की आवश्यकता है __FILE__और __LINE__ यह भी पूर्वप्रक्रमक आवश्यकता होती है। उन्हें अपने कोड में उपयोग करना प्रीप्रोसेसर के लिए एक संक्रमण वेक्टर की तरह है।
TED

93

विधियाँ हमेशा पूर्ण, अनिवार्य कोड होनी चाहिए; मैक्रो कोड के टुकड़े हो सकते हैं। इस प्रकार आप एक फॉर्च्यूनिक मैक्रो को परिभाषित कर सकते हैं:

#define foreach(list, index) for(index = 0; index < list.size(); index++)

और इसका उपयोग इस प्रकार करें:

foreach(cookies, i)
    printf("Cookie: %s", cookies[i]);

C ++ 11 के बाद से, यह लूप के लिए रेंज-आधारित द्वारा सुधारा गया है ।


6
+1 यदि आप कुछ हास्यास्पद जटिल इटिरेक्टर सिंटैक्स का उपयोग कर रहे हैं, तो फ़ॉरच स्टाइल स्टाइल मैक्रो लिखने से आपका कोड पढ़ने और बनाए रखने में बहुत आसान हो सकता है। मैंने इसे किया है, यह काम करता है।
पोस्टफुटुरिस्ट

9
अधिकांश टिप्पणियां इस बात के लिए पूरी तरह अप्रासंगिक हैं कि मैक्रोज़ पूर्ण कोड के बजाय कोड के टुकड़े हो सकते हैं। लेकिन नाइटपैकिंग के लिए धन्यवाद।
jddichal

12
यह C नहीं C ++ है। यदि आप C ++ कर रहे हैं, तो आपको iterators और std :: for_each का उपयोग करना चाहिए।
19:11 बजे

20
मैं असहमत हूं, संजो रहा हूं। लैम्ब्डा से पहले, for_eachएक बुरा काम था, क्योंकि प्रत्येक तत्व के माध्यम से रननेनिग कोड को कॉलिंग पॉइंट के लिए स्थानीय नहीं था। foreach, (और मैं BOOST_FOREACHहाथ से लुढ़का हुआ समाधान के बजाय अत्यधिक अनुशंसा करता हूं ) चलो आपको कोड को पुनरावृत्ति साइट के पास रखते हैं, जिससे यह अधिक पठनीय बन जाता है। एक बार लैंबडा का रोल आउट करने के बाद, for_eachएक बार फिर से जाने का रास्ता हो सकता है।
GManNickG

8
और यह ध्यान देने योग्य है कि BOOST_FOREACH अपने आप में एक मैक्रो है (लेकिन बहुत अच्छी तरह से सोचा-समझा एक)
टायलर मैकहेनरी

59

हैडर फ़ाइल गार्ड को मैक्रोज़ की आवश्यकता होती है।

क्या कोई अन्य क्षेत्र हैं जो मैक्रोज़ की आवश्यकता है? बहुत नहीं (यदि कोई हो)।

क्या ऐसी कोई अन्य परिस्थितियाँ हैं जो मैक्रोज़ को लाभ पहुँचाती हैं? हाँ!!!

मैक्रोज़ का उपयोग करने वाला एक स्थान बहुत ही दोहराव वाले कोड के साथ है। उदाहरण के लिए, जब C ++ कोड को अन्य इंटरफेस (.NET, COM, पायथन, आदि ...) के साथ उपयोग किया जाता है, तो मुझे विभिन्न प्रकार के अपवादों को पकड़ना होगा। यहां बताया गया है कि मैं यह कैसे कर सकता हूं:

#define HANDLE_EXCEPTIONS \
catch (::mylib::exception& e) { \
    throw gcnew MyDotNetLib::Exception(e); \
} \
catch (::std::exception& e) { \
    throw gcnew MyDotNetLib::Exception(e, __LINE__, __FILE__); \
} \
catch (...) { \
    throw gcnew MyDotNetLib::UnknownException(__LINE__, __FILE__); \
}

मुझे ये कैच हर रैपर फंक्शन में लगाना है। हर बार पूर्ण पकड़ने वाले ब्लॉक को टाइप करने के बजाय, मैं सिर्फ टाइप करता हूं:

void Foo()
{
    try {
        ::mylib::Foo()
    }
    HANDLE_EXCEPTIONS
}

इससे रखरखाव भी आसान हो जाता है। अगर मुझे कभी भी एक नया अपवाद प्रकार जोड़ना है, तो मुझे इसे जोड़ने के लिए केवल एक जगह की आवश्यकता है।

अन्य उपयोगी उदाहरण भी हैं: जिनमें से कई में __FILE__और __LINE__प्रीप्रोसेसर मैक्रोज़ शामिल हैं।

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


7
अधिकांश कंपाइलर #pragma onceइन दिनों का समर्थन करते हैं, इसलिए मुझे संदेह है कि गार्ड वास्तव में आवश्यक हैं
1800 इंफोर्मेशन

13
वे अगर आप केवल सभी के बजाय सभी संकलक के लिए लिख रहे हैं ;-)
स्टीव जेसप

30
तो पोर्टेबल, मानक प्रीप्रोसेसर कार्यक्षमता के बजाय, आप प्रीप्रोसेसर का उपयोग करने से बचने के लिए प्रीप्रोसेसर एक्सटेंशन का उपयोग करने की सलाह देते हैं? मुझे हास्यास्पद लगता है।
लोगान कैपाल्डो

#pragma onceकई आम बिल्ड सिस्टम पर टूट जाता है।
मील्स रूट

4
इसके लिए एक समाधान है कि मैक्रोज़ की आवश्यकता नहीं है void handleExceptions(){ try { throw } catch (::mylib::exception& e) {....} catch (::std::exception& e) {...} ... }:। और फ़ंक्शन पक्ष पर:void Foo(){ try {::mylib::Foo() } catch (...) {handleExceptions(); } }
माइक एमबी

51

अधिकतर:

  1. गार्ड शामिल करें
  2. सशर्त संकलन
  3. रिपोर्टिंग (पूर्वनिर्धारित मैक्रो जैसी __LINE__और __FILE__)
  4. (शायद ही कभी) दोहरावदार कोड पैटर्न दोहराए।
  5. आपके प्रतियोगी कोड में।

संख्या 5 को महसूस करने के बारे में कुछ मदद की तलाश में। क्या आप मुझे समाधान की दिशा में मार्गदर्शन कर सकते हैं?
मैक्स

50

संकलक के बीच अंतर के मुद्दों को दूर करने के लिए सशर्त संकलन के अंदर:

#ifdef ARE_WE_ON_WIN32
#define close(parm1)            _close (parm1)
#define rmdir(parm1)            _rmdir (parm1)
#define mkdir(parm1, parm2)     _mkdir (parm1)
#define access(parm1, parm2)    _access(parm1, parm2)
#define create(parm1, parm2)    _creat (parm1, parm2)
#define unlink(parm1)           _unlink(parm1)
#endif

12
C ++ में, इनलाइन फ़ंक्शंस के उपयोग के माध्यम से समान प्राप्त किया जा सकता है: <code> #ifdef ARE_WE_ON_WIN32 <br> इनलाइन इंट क्लोज़ (int i) {return _close (i); } <br> #endif </ code>
पृष्ठ २२:३०

2
जो # डिफाइनेंस को हटाता है, लेकिन # हाइडीफ और # वेंडीफ को नहीं। वैसे भी, मैं आपसे सहमत हूं।
गोरिपिक

19
कभी भी निचले मामले के मैक्रो को परिभाषित न करें। फ़ंक्शन को बदलने के लिए मैक्रोज़ मेरे बुरे सपने हैं (आपको धन्यवाद Microsoft)। सबसे अच्छा उदाहरण पहली पंक्ति में है। कई पुस्तकालयों में closeकार्य या विधियां हैं। फिर जब आप इस लाइब्रेरी के हेडर को शामिल करते हैं और इस मैक्रो के हेडर से आपको कोई बड़ी समस्या होती है, तो आप लाइब्रेरी एपीआई का उपयोग करने में असमर्थ होते हैं।
मारेक आर

एंड्रयूसेन, क्या आपको @ पियर्सबल के सुझाव पर इस संदर्भ में मैक्रोज़ के उपयोग का कोई लाभ मिलता है? यदि नहीं, तो ऐसा लगता है कि मैक्रोज़ वास्तव में आभारी हैं।
einpoklum


38

जब आप एक स्ट्रिंग को एक अभिव्यक्ति से बाहर करना चाहते हैं, तो इसके लिए सबसे अच्छा उदाहरण है assert( स्ट्रिंग #xके मूल्य को बदल देता है x)।

#define ASSERT_THROW(condition) \
if (!(condition)) \
     throw std::exception(#condition " is false");

5
बस एक निपिक, लेकिन मैं व्यक्तिगत रूप से अर्धविराम को छोड़ दूंगा।
माइकल मायर्स

10
मैं सहमत हूं, वास्तव में मैं इसे एक {{जबकि (झूठा) (और हाईजैकिंग को रोकने के लिए) करना चाहूंगा लेकिन मैं इसे बहुत सरल रखना चाहता था।
मत्ती

33

स्ट्रिंग स्थिरांक को कभी-कभी मैक्रोज़ के रूप में बेहतर रूप से परिभाषित किया जाता है क्योंकि आप स्ट्रिंग के साथ और अधिक कर सकते हैं const char *

उदाहरण के लिए स्ट्रिंग शाब्दिक को आसानी से समेटा जा सकता है ।

#define BASE_HKEY "Software\\Microsoft\\Internet Explorer\\"
// Now we can concat with other literals
RegOpenKey(HKEY_CURRENT_USER, BASE_HKEY "Settings", &settings);
RegOpenKey(HKEY_CURRENT_USER, BASE_HKEY "TypedURLs", &URLs);

यदि const char *उपयोग किया जाता था, तो रन टाइम पर किसी प्रकार के स्ट्रिंग क्लास का उपयोग प्रदर्शन करने के लिए किया जाता था:

const char* BaseHkey = "Software\\Microsoft\\Internet Explorer\\";
RegOpenKey(HKEY_CURRENT_USER, (string(BaseHkey) + "Settings").c_str(), &settings);
RegOpenKey(HKEY_CURRENT_USER, (string(BaseHkey) + "TypedURLs").c_str(), &URLs);

2
C ++ 11 में, मैं इसे सबसे महत्वपूर्ण हिस्सा (गार्ड शामिल करने के अलावा) मानूंगा। मैक्रों वास्तव में सबसे अच्छी चीज है जो हमारे पास संकलन-समय स्ट्रिंग प्रसंस्करण के लिए है। यह एक ऐसी विशेषता है जो मुझे आशा है कि हमें
डेविड स्टोन

1
यह वह स्थिति है जिसके कारण मुझे C # में मैक्रोज़ की इच्छा हुई।
कच्चे

2
काश मैं यह +42 कर सकता। एक बहुत ही महत्वपूर्ण, हालांकि अक्सर स्ट्रिंग शाब्दिक का याद नहीं किया गया पहलू।
डैनियल कामिल कोजार

24

जब आप किसी फ़ंक्शन में प्रोग्राम फ्लो ( और return, ) कोड को बदलना चाहते हैं , तो कोड से भिन्न व्यवहार करता है जो वास्तव में फ़ंक्शन में इनबिल्ड है।breakcontinue

#define ASSERT_RETURN(condition, ret_val) \
if (!(condition)) { \
    assert(false && #condition); \
    return ret_val; }

// should really be in a do { } while(false) but that's another discussion.

एक अपवाद को फेंकना मुझे एक बेहतर विकल्प की तरह लगता है।
ईनपोकलूम

जब पायथन सी (++) एक्सटेंशन लिखते हैं, तो अपवाद स्ट्रिंग को सेट करके अपवादों का प्रचार किया जाता है, फिर वापस -1या NULL। तो एक मैक्रो बॉयलरप्लेट कोड को बहुत कम कर सकता है।
black_puppydog

20

स्पष्ट में गार्ड शामिल हैं

#ifndef MYHEADER_H
#define MYHEADER_H

...

#endif

17

आप एक नियमित फ़ंक्शन कॉल का उपयोग करके फ़ंक्शन कॉल तर्कों की शॉर्ट-सर्कुलेटिंग नहीं कर सकते। उदाहरण के लिए:

#define andm(a, b) (a) && (b)

bool andf(bool a, bool b) { return a && b; }

andm(x, y) // short circuits the operator so if x is false, y would not be evaluated
andf(x, y) // y will always be evaluated

3
हो सकता है कि एक अधिक सामान्य बिंदु: कार्य उनके तर्कों का ठीक एक बार मूल्यांकन करें। मैक्रोज़ तर्कों का मूल्यांकन अधिक या कम बार कर सकते हैं।
स्टीव जेसोप

@ [ग्रेग रोजर्स] सभी मैक्रो प्रीप्रोसेसर करता है विकल्प पाठ है। एक बार जब आप समझ जाते हैं कि, इसके बारे में अधिक रहस्य नहीं होना चाहिए।
1800 सूचना

आप फ़ंक्शन को कॉल करने से पहले बूल को मूल्यांकन के लिए मजबूर करने के बजाय templatizing औरf द्वारा समान व्यवहार प्राप्त कर सकते हैं। मुझे एहसास नहीं होता कि आपने जो कहा, वह अपने लिए कोशिश किए बिना सच था। दिलचस्प।
ग्रेग रोजर्स

एक टेम्पलेट के साथ आप वास्तव में ऐसा कैसे कर सकते हैं?
--०० सूचना

6
एक फंक्शन स्टाइल मैक्रो के पीछे शॉर्ट-सर्कुलेटिंग ऑपरेशन्स को छिपाना उन चीजों में से एक है जिन्हें मैं वास्तव में प्रोडक्शन कोड में नहीं देखना चाहता।
माइकबीएम जूल

17

मान लीजिए कि हम हेडर गार्ड जैसी स्पष्ट चीजों को अनदेखा करेंगे।

कभी-कभी, आप उस कोड को उत्पन्न करना चाहते हैं जिसे precompiler द्वारा कॉपी / पेस्ट किया जाना है:

#define RAISE_ERROR_STL(p_strMessage)                                          \
do                                                                             \
{                                                                              \
   try                                                                         \
   {                                                                           \
      std::tstringstream strBuffer ;                                           \
      strBuffer << p_strMessage ;                                              \
      strMessage = strBuffer.str() ;                                           \
      raiseSomeAlert(__FILE__, __FUNCSIG__, __LINE__, strBuffer.str().c_str()) \
   }                                                                           \
   catch(...){}                                                                \
   {                                                                           \
   }                                                                           \
}                                                                              \
while(false)

जो आपको यह कोड करने में सक्षम बनाता है:

RAISE_ERROR_STL("Hello... The following values " << i << " and " << j << " are wrong") ;

और संदेश उत्पन्न कर सकते हैं जैसे:

Error Raised:
====================================
File : MyFile.cpp, line 225
Function : MyFunction(int, double)
Message : "Hello... The following values 23 and 12 are wrong"

ध्यान दें कि मैक्रोज़ के साथ टेम्प्लेट मिलाने से और भी बेहतर परिणाम मिल सकते हैं (यानी अपने वैरिएबल नामों के साथ-साथ वैल्यू को साथ-साथ पैदा करना)

उदाहरण के लिए, डिबग जानकारी उत्पन्न करने के लिए, दूसरी बार, आपको कुछ कोड के __FILE__ और / या __LINE__ की आवश्यकता होती है। निम्नलिखित दृश्य C ++ के लिए एक क्लासिक है:

#define WRNG_PRIVATE_STR2(z) #z
#define WRNG_PRIVATE_STR1(x) WRNG_PRIVATE_STR2(x)
#define WRNG __FILE__ "("WRNG_PRIVATE_STR1(__LINE__)") : ------------ : "

निम्नलिखित कोड के साथ के रूप में:

#pragma message(WRNG "Hello World")

यह संदेश उत्पन्न करता है जैसे:

C:\my_project\my_cpp_file.cpp (225) : ------------ Hello World

दूसरी बार, आपको # और ## कॉन्फैक्शन ऑपरेटर्स का उपयोग करके कोड जेनरेट करने की आवश्यकता होती है, जैसे प्रॉपर्टी के लिए गेटर्स और सेटर्स जेनरेट करना (यह काफी सीमित मामलों के लिए होता है)।

अन्य बार, यदि आप एक फ़ंक्शन के माध्यम से उपयोग किया जाता है, तो आप संकलन नहीं करेंगे, जैसे:

#define MY_TRY      try{
#define MY_CATCH    } catch(...) {
#define MY_END_TRY  }

जिसका उपयोग किया जा सकता है

MY_TRY
   doSomethingDangerous() ;
MY_CATCH
   tryToRecoverEvenWithoutMeaningfullInfo() ;
   damnThoseMacros() ;
MY_END_TRY

(अब भी, मैं सिर्फ सही इस्तेमाल किया कोड के इस प्रकार देखा एक बार )

अंतिम, लेकिन कम से कम, प्रसिद्ध नहीं boost::foreach!!!

#include <string>
#include <iostream>
#include <boost/foreach.hpp>

int main()
{
    std::string hello( "Hello, world!" );

    BOOST_FOREACH( char ch, hello )
    {
        std::cout << ch;
    }

    return 0;
}

(नोट: कोड कॉपी / बूस्ट होमपेज से चिपकाया गया)

जो (IMHO) से बेहतर तरीका है std::for_each

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


1
केवल कंपाइलर क्या नहीं कर सकता, इसके लिए CPP का उपयोग करें। उदाहरण के लिए, RAISE_ERROR_STL को CPP का उपयोग केवल फ़ाइल, लाइन और फंक्शन सिग्नेचर को निर्धारित करने के लिए करना चाहिए, और उन फंक्शन (संभवतः इनलाइन) को पास करना चाहिए जो बाकी काम करता है।
रेनर ब्लोम

कृपया C ++ 11 को दर्शाने के लिए अपने उत्तर को अपडेट करें और @ RainerBlome की टिप्पणी को संबोधित करें।
ईनपोकलूम

@ रेनरब्लोम: हम सहमत हैं। RAISE_ERROR_STL मैक्रो प्री-सी ++ 11 है, इसलिए उस संदर्भ में, यह पूरी तरह से उचित है। मेरी समझ (लेकिन मेरे पास उन विशिष्ट विशेषताओं से निपटने का अवसर कभी नहीं था) यह है कि आप समस्या को अधिक सुरुचिपूर्ण ढंग से हल करने के लिए आधुनिक C ++ में वैरेडिक टेम्प्लेट (या मैक्रोज़?) का उपयोग कर सकते हैं।
पियरसबल

@einpoklum: "कृपया C ++ 11 को प्रतिबिंबित करने के लिए अपने उत्तर को अपडेट करें और रेनब्लोम की टिप्पणी" नहीं :-)। । । मेरा मानना ​​है कि सबसे अच्छा, मैं आधुनिक C ++ के लिए एक अनुभाग जोड़ूंगा, वैकल्पिक कार्यान्वयन में मैक्रोज़ की आवश्यकता को कम करने या समाप्त करने के साथ, लेकिन बिंदु खड़ा है: मैक्रोज़ बदसूरत और बुरे हैं, लेकिन जब आपको कुछ करने की आवश्यकता होती है तो संकलक समझ में नहीं आता है , आप इसे मैक्रोज़ के माध्यम से करते हैं।
पियरसबल

यहां तक ​​कि C ++ 11 के साथ, आपके मैक्रो क्या करता है का एक बहुत कुछ करने के लिए एक समारोह के लिए छोड़ा जा सकता है: #include <sstream> #include <iostream> using namespace std; void trace(char const * file, int line, ostream & o) { cerr<<file<<":"<<line<<": "<< static_cast<ostringstream & >(o).str().c_str()<<endl; } struct Oss { ostringstream s; ostringstream & lval() { return s; } }; #define TRACE(ostreamstuff) trace(__FILE__, __LINE__, Oss().lval()<<ostreamstuff) int main() { TRACE("Hello " << 123); return 0; }इस तरह, मैक्रो छोटा रास्ता है।
रेनर ब्लोम

16

C ++ के लिए यूनिट टेस्ट फ्रेमवर्क जैसे UnitTest ++ बहुत ज्यादा प्रीप्रोसेसर मैक्रोज़ के चारों ओर घूमते हैं। यूनिट टेस्ट कोड की कुछ पंक्तियों का विस्तार उन कक्षाओं के एक पदानुक्रम में होता है जो मैन्युअल रूप से टाइप करने के लिए मज़ेदार नहीं होंगे। UnitTest ++ की तरह कुछ के बिना और यह प्रीप्रोसेसर जादू है, मुझे नहीं पता कि आप कुशलतापूर्वक C ++ के लिए यूनिट परीक्षण कैसे लिखेंगे।


बिना किसी रूपरेखा के लिखना संभव नहीं है। अंत में, यह केवल इस बात पर निर्भर करता है कि आपको किस तरह का आउटपुट चाहिए। यदि आप परवाह नहीं करते हैं, तो सफलता या विफलता का संकेत देने वाला एक साधारण निकास मूल्य पूरी तरह से ठीक होना चाहिए।
क्लियर

15

सी प्रीप्रोसेसर को डराने के लिए गरमागरम बल्बों से डरना पसंद है क्योंकि हमें फ्लोरोसेंट बल्ब मिलते हैं। हाँ, पूर्व हो सकता है {बिजली | प्रोग्रामर समय} अक्षम। हाँ, आप (शाब्दिक) उनके द्वारा जलाए जा सकते हैं। लेकिन वे काम कर सकते हैं यदि आप इसे ठीक से संभालते हैं।

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

अलेक्जेंडर स्टेपानोव कहते हैं :

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


मुझे लगता है कि यह गलत रवैया है। सिर्फ इसलिए कि आप "इसे ठीक से संभालना" सीख सकते हैं इसका मतलब यह नहीं है कि यह किसी के समय और प्रयास के लायक है।
नील जी

9

हम का उपयोग करें __FILE__और __LINE__एक साथ जानकारी अमीर अपवाद फेंकने में नैदानिक प्रयोजनों, को पकड़ने और प्रवेश के लिए मैक्रो, हमारे गुणवत्ता आश्वासन के बुनियादी ढांचे में स्वचालित लॉग फ़ाइल स्कैनर के साथ।

उदाहरण के लिए, एक फेंकने वाले मैक्रो OUR_OWN_THROWका उपयोग उस अपवाद के लिए अपवाद प्रकार और निर्माण मापदंडों के साथ किया जा सकता है, जिसमें एक पाठ्य विवरण भी शामिल है। ऐशे ही:

OUR_OWN_THROW(InvalidOperationException, (L"Uninitialized foo!"));

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


9

कोड पुनरावृत्ति।

प्रीप्रोसेसर लाइब्रेरी को बढ़ावा देने के लिए एक नज़र डालें , यह एक तरह का मेटा-मेटा-प्रोग्रामिंग है। विषय-> प्रेरणा में आप एक अच्छा उदाहरण पा सकते हैं।


मैं लगभग सभी, यदि सभी नहीं, तो मामलों - कोड की पुनरावृत्ति को फ़ंक्शन कॉल से बचा जा सकता है।
ईनपोकलूम

@einpoklum: मैं सहमत नहीं हूँ। लिंक पर एक नजर है
रग्गरो तुर्रा

9

कुछ बहुत ही उन्नत और उपयोगी सामान अभी भी प्रीप्रोसेसर (मैक्रोज़) का उपयोग करके बनाया जा सकता है, जिसे आप टेम्प्लेट सहित c ++ "भाषा निर्माण" का उपयोग करके कभी नहीं कर पाएंगे।

उदाहरण:

एक सी पहचानकर्ता और एक स्ट्रिंग दोनों कुछ बनाना

सी में स्ट्रिंग के रूप में एनम प्रकारों के चर का उपयोग करने का आसान तरीका

बूस्ट प्रीप्रोसेसर मेटाप्रोग्रामिंग


तीसरी कड़ी टूटी है
रॉबिन हार्टलैंड

बेहतर समझने के लिए एक नज़र डालें stdio.hऔर sal.hफ़ाइल करें vc12
एलशान १

7

मैं कभी-कभी मैक्रोज़ का उपयोग करता हूं इसलिए मैं एक स्थान पर जानकारी को परिभाषित कर सकता हूं, लेकिन कोड के विभिन्न हिस्सों में इसे अलग-अलग तरीकों से उपयोग कर सकता हूं। यह केवल थोड़ी बुराई है :)

उदाहरण के लिए, "field_list.h" में:

/*
 * List of fields, names and values.
 */
FIELD(EXAMPLE1, "first example", 10)
FIELD(EXAMPLE2, "second example", 96)
FIELD(ANOTHER, "more stuff", 32)
...
#undef FIELD

फिर एक सार्वजनिक गणना के लिए इसे केवल नाम का उपयोग करने के लिए परिभाषित किया जा सकता है:

#define FIELD(name, desc, value) FIELD_ ## name,

typedef field_ {

#include "field_list.h"

    FIELD_MAX

} field_en;

और एक निजी इनिट फ़ंक्शन में, सभी फ़ील्ड्स को डेटा के साथ तालिका पॉप्युलेट करने के लिए उपयोग किया जा सकता है:

#define FIELD(name, desc, value) \
    table[FIELD_ ## name].desc = desc; \
    table[FIELD_ ## name].value = value;

#include "field_list.h"

1
नोट: इसी तरह की तकनीक को अलग किए बिना भी लागू किया जा सकता है। देखें: stackoverflow.com/questions/147267/… stackoverflow.com/questions/126277/…
सुमा

6

एक सामान्य उपयोग संकलन वातावरण का पता लगाने के लिए है, क्रॉस-प्लेटफॉर्म विकास के लिए आप लिनक्स के लिए कोड का एक सेट लिख सकते हैं, कह सकते हैं, और दूसरा विंडोज़ के लिए जब कोई क्रॉस प्लेटफॉर्म लाइब्रेरी आपके उद्देश्यों के लिए पहले से मौजूद नहीं है।

तो, एक मोटे उदाहरण में एक क्रॉस-प्लेटफॉर्म म्यूटेक्स हो सकता है

void lock()
{
    #ifdef WIN32
    EnterCriticalSection(...)
    #endif
    #ifdef POSIX
    pthread_mutex_lock(...)
    #endif
}

फ़ंक्शंस के लिए, वे तब उपयोगी होते हैं जब आप प्रकार की सुरक्षा को स्पष्ट रूप से अनदेखा करना चाहते हैं। जैसे ASSERT करने के लिए ऊपर और नीचे कई उदाहरण। बेशक, बहुत सी / सी ++ सुविधाओं की तरह आप अपने आप को पैर में गोली मार सकते हैं, लेकिन भाषा आपको उपकरण देती है और आपको यह तय करने देती है कि आपको क्या करना है।


चूंकि प्रश्नकर्ता ने पूछा: यह मैक्रोज़ के बिना अलग-अलग हेडर के माध्यम से प्रति प्लेटफॉर्म में अलग-अलग पथों को शामिल करके किया जा सकता है। मैं सहमत हूँ कि मैक्रों अक्सर अधिक सुविधाजनक होते हैं।
स्टीव जेसोप

मुझे भी वह पता हैं। यदि आप उस उद्देश्य के लिए मैक्रोज़ का उपयोग करना शुरू करते हैं, तो कोड जल्दी से बहुत कम पठनीय बन सकता है
नेमेनजा ट्रिफ़ुनोविक

6

कुछ इस तरह

void debugAssert(bool val, const char* file, int lineNumber);
#define assert(x) debugAssert(x,__FILE__,__LINE__);

ताकि आप सिर्फ उदाहरण के लिए कर सकते हैं

assert(n == true);

और यदि n गलत है, तो अपने लॉग आउट के लिए प्रिंट की गई समस्या का स्रोत फ़ाइल नाम और लाइन नंबर प्राप्त करें।

यदि आप एक सामान्य फ़ंक्शन कॉल का उपयोग करते हैं जैसे कि

void assert(bool val);

मैक्रो के बजाय, आप जो भी प्राप्त कर सकते हैं, वह आपके एसेटर फ़ंक्शन की लॉग के लिए छपी हुई संख्या है, जो कम उपयोगी होगी।


जब आप पहले से <cassert>ही assert()मैक्रो, जो फ़ाइल / लाइन / फ़ंक्शन जानकारी को डंप करते हैं, मानक लाइब्रेरी के कार्यान्वयन प्रदान करते हैं तो आप पहिया को क्यों सुदृढ़ करेंगे ? (सभी कार्यान्वयनों में, मैंने वैसे भी देखा है)
अंडरस्कोर_ड

4
#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])

वर्तमान थ्रेड में चर्चा किए गए 'पसंदीदा' टेम्पलेट समाधान के विपरीत, आप इसे एक स्थिर अभिव्यक्ति के रूप में उपयोग कर सकते हैं:

char src[23];
int dest[ARRAY_SIZE(src)];

2
इसे एक सुरक्षित तरीके से टेम्प्लेट के साथ किया जा सकता है (जो किसी सरणी के बजाय पॉइंटर को पास नहीं करेगा) stackoverflow.com/questions/720077/calculating-size-of-an-array/…
Mottor

1
अब जब हमारे पास C ++ 11 में बाधा है, तो सुरक्षित (गैर-मैक्रो) संस्करण का उपयोग निरंतर अभिव्यक्ति में भी किया जा सकता है। template<typename T, std::size_t size> constexpr std::size_t array_size(T const (&)[size]) { return size; }
डेविड स्टोन

3

आप डिबगिंग और यूनिट परीक्षण परिदृश्यों की सहायता के लिए #defines का उपयोग कर सकते हैं। उदाहरण के लिए, मेमोरी फ़ंक्शंस के विशेष लॉगिंग वेरिएंट बनाएं और एक विशेष memlog_preinclude.h बनाएँ:

#define malloc memlog_malloc
#define calloc memlog calloc
#define free memlog_free

आप का उपयोग कर कोड संकलित करें:

gcc -Imemlog_preinclude.h ...

अंतिम छवि में अपने memlog.o में एक लिंक। अब आप मॉलॉक आदि को नियंत्रित करते हैं, शायद लॉगिंग उद्देश्यों के लिए, या यूनिट परीक्षणों के लिए आवंटन विफलताओं का अनुकरण करने के लिए।


3

जब आप कंपाइलर / ओएस / हार्डवेयर विशिष्ट व्यवहार पर संकलन समय पर निर्णय ले रहे हैं।

यह आपको Comppiler / OS / Hardware की विशिष्ट विशेषताओं के लिए अपना इंटरफ़ेस बनाने की अनुमति देता है।

#if defined(MY_OS1) && defined(MY_HARDWARE1)
#define   MY_ACTION(a,b,c)      doSothing_OS1HW1(a,b,c);}
#elif define(MY_OS1) && defined(MY_HARDWARE2)
#define   MY_ACTION(a,b,c)      doSomthing_OS1HW2(a,b,c);}
#elif define(MY_SUPER_OS)
          /* On this hardware it is a null operation */
#define   MY_ACTION(a,b,c)
#else
#error  "PLEASE DEFINE MY_ACTION() for this Compiler/OS/HArdware configuration"
#endif

3

मैं आसानी से परिभाषित करने के लिए मैक्रोज़ का उपयोग करता हूं:

DEF_EXCEPTION(RessourceNotFound, "Ressource not found")

जहां DEF_EXCEPTION है

#define DEF_EXCEPTION(A, B) class A : public exception\
  {\
  public:\
    virtual const char* what() const throw()\
    {\
      return B;\
    };\
  }\

2

कंपाइलर आपके अनुरोध को इनलाइन से मना कर सकते हैं।

मैक्रों की हमेशा अपनी जगह होगी।

डिबग ट्रेसिंग के लिए मुझे जो कुछ उपयोगी लगता है वह है #define DEBUG - आप इसे 1 छोड़ सकते हैं जब किसी समस्या को डीबग करते हुए (या पूरे विकास चक्र के दौरान इसे छोड़ भी सकते हैं) तब इसे बंद कर दें जब यह जहाज करने का समय हो।


10
यदि संकलक आपके अनुरोध को इनलाइन से मना करता है, तो इसका एक बहुत अच्छा कारण हो सकता है। एक अच्छा कंपाइलर आपके मुकाबले ठीक से इनलाइनिंग में बेहतर होगा, और एक बुरा आपको इससे ज्यादा परफॉर्मेंस प्रॉब्लम देगा।
डेविड थॉर्नले

@DavidThornley या यह GCC या CLANG / LLVM की तरह एक महान अनुकूलन संकलक नहीं हो सकता है। कुछ संकलक सिर्फ बकवास हैं।
मील्स राउत

2

अपनी आखिरी नौकरी में, मैं एक वायरस स्कैनर पर काम कर रहा था। डिबग करना मेरे लिए आसान बनाने के लिए, मैंने सभी जगह बहुत सारे लॉगिंग अटके हुए थे, लेकिन इस तरह के उच्च मांग वाले ऐप में, फ़ंक्शन कॉल का खर्च अभी बहुत महंगा है। इसलिए, मैं इस छोटे से मैक्रों के साथ आया, जिसने अभी भी मुझे एक ग्राहक साइट पर एक रिलीज़ संस्करण पर डिबग लॉगिंग को सक्षम करने की अनुमति दी, बिना फ़ंक्शन कॉल की लागत के डिबग ध्वज की जांच करेगा और बस कुछ भी लॉग किए बिना वापस लौटाएगा, या सक्षम होने पर। , लॉगिंग करेंगे ... मैक्रो को निम्नानुसार परिभाषित किया गया था:

#define dbgmsg(_FORMAT, ...)  if((debugmsg_flag  & 0x00000001) || (debugmsg_flag & 0x80000000))     { log_dbgmsg(_FORMAT, __VA_ARGS__);  }

लॉग फ़ंक्शंस में VA_ARGS की वजह से इस तरह के मैक्रो के लिए यह एक अच्छा मामला था।

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

मैक्रो (एस) के रूप में परिभाषित:

#define SECURITY_CHECK(lRequiredSecRoles) if(!DoSecurityCheck(lRequiredSecRoles, #lRequiredSecRoles, true)) return
#define SECURITY_CHECK_QUIET(lRequiredSecRoles) (DoSecurityCheck(lRequiredSecRoles, #lRequiredSecRoles, false))

फिर, हम सिर्फ यूआई पर चेक छिड़क सकते हैं, और यह आपको बताएगा कि उन भूमिकाओं को करने की अनुमति दी गई थी जो आपने करने की कोशिश की थी, अगर आपके पास पहले से ही वह भूमिका नहीं थी। उनमें से दो का कारण कुछ स्थानों पर एक मूल्य वापस करना था, और दूसरों में एक शून्य फ़ंक्शन से वापस लौटना ...

SECURITY_CHECK(ROLE_BUSINESS_INFORMATION_STEWARD | ROLE_WORKER_ADMINISTRATOR);

LRESULT CAddPerson1::OnWizardNext() 
{
   if(m_Role.GetItemData(m_Role.GetCurSel()) == parent->ROLE_EMPLOYEE) {
      SECURITY_CHECK(ROLE_WORKER_ADMINISTRATOR | ROLE_BUSINESS_INFORMATION_STEWARD ) -1;
   } else if(m_Role.GetItemData(m_Role.GetCurSel()) == parent->ROLE_CONTINGENT) {
      SECURITY_CHECK(ROLE_CONTINGENT_WORKER_ADMINISTRATOR | ROLE_BUSINESS_INFORMATION_STEWARD | ROLE_WORKER_ADMINISTRATOR) -1;
   }
...

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


2

फिर भी एक और फॉरेक्स मैक्रोज़। टी: प्रकार, सी: कंटेनर, मैं: पुनरावृत्ति

#define foreach(T, c, i) for(T::iterator i=(c).begin(); i!=(c).end(); ++i)
#define foreach_const(T, c, i) for(T::const_iterator i=(c).begin(); i!=(c).end(); ++i)

उपयोग (अवधारणा दिखा रहा है, वास्तविक नहीं):

void MultiplyEveryElementInList(std::list<int>& ints, int mul)
{
    foreach(std::list<int>, ints, i)
        (*i) *= mul;
}

int GetSumOfList(const std::list<int>& ints)
{
    int ret = 0;
    foreach_const(std::list<int>, ints, i)
        ret += *i;
    return ret;
}

बेहतर कार्यान्वयन उपलब्ध हैं: Google "BOOST_FOREACH"

अच्छे लेख उपलब्ध हैं: सशर्त प्यार: पूर्व रेडक्स (एरिक नीब्लर) http://www.artima.com/cppsource/forc.html


2

शायद मैक्रों का महान उपयोग प्लेटफॉर्म-स्वतंत्र विकास में है। टाइप असंगति के मामलों के बारे में सोचें - मैक्रोज़ के साथ, आप बस विभिन्न हेडर फ़ाइलों का उपयोग कर सकते हैं - जैसे: - WIN_TYPESH

typedef ...some struct

--POSIX_TYPES.h

typedef ...some another struct

--program.h

#ifdef WIN32
#define TYPES_H "WINTYPES.H"
#else 
#define TYPES_H "POSIX_TYPES.H"
#endif

#include TYPES_H

अन्य तरीकों से इसे लागू करने से ज्यादा पठनीय, मेरी राय में।


2

लगता है VA_ARGS का केवल अब तक अप्रत्यक्ष रूप से उल्लेख किया गया है:

जेनेरिक C ++ 03 कोड लिखते समय, और आपको (जेनेरिक) मापदंडों की एक चर संख्या की आवश्यकता होती है, आप टेम्पलेट के बजाय मैक्रो का उपयोग कर सकते हैं।

#define CALL_RETURN_WRAPPER(FnType, FName, ...)          \
  if( FnType theFunction = get_op_from_name(FName) ) {   \
    return theFunction(__VA_ARGS__);                     \
  } else {                                               \
    throw invalid_function_name(FName);                  \
  }                                                      \
/**/

नोट: सामान्य तौर पर, नाम जाँच / फेंक को काल्पनिक get_op_from_nameफ़ंक्शन में भी शामिल किया जा सकता है। यह सिर्फ एक उदाहरण है। VA_ARGS कॉल के आसपास अन्य सामान्य कोड हो सकते हैं।

एक बार जब हम C ++ 11 के साथ वैरेडिक टेम्प्लेट प्राप्त करते हैं, तो हम इस "ठीक से" एक टेम्प्लेट के साथ हल कर सकते हैं।


1

मुझे लगता है कि यह ट्रिक प्रीप्रोसेसर का एक चतुर उपयोग है जिसे एक फ़ंक्शन के साथ अनुकरण नहीं किया जा सकता है:

#define COMMENT COMMENT_SLASH(/)
#define COMMENT_SLASH(s) /##s

#if defined _DEBUG
#define DEBUG_ONLY
#else
#define DEBUG_ONLY COMMENT
#endif

तो आप इसे इस तरह से उपयोग कर सकते हैं:

cout <<"Hello, World!" <<endl;
DEBUG_ONLY cout <<"This is outputed only in debug mode" <<endl;

आप RELEASE_ONLY मैक्रो को भी परिभाषित कर सकते हैं।


2
यह ट्रिक मानक के अनुसार काम नहीं करती है। यह प्रीप्रोसेसर के माध्यम से एक टिप्पणी मार्कर बनाने का प्रयास करता है, लेकिन प्रीप्रोसेसर के चलने से पहले टिप्पणियां हटा दी जाती हैं। एक अनुरूप संकलक यहाँ एक वाक्यविन्यास त्रुटि का कारण होगा।
डेविड थॉर्नले

2
क्षमा करें, लेकिन डेविड को टिप्पणी हटाने की दूसरी प्रति शामिल करनी चाहिए।
जोशुआ

डिबगिंग फ़्लैग को ग्लोबल कॉस्ट बूल बनाने में बहुत आसान है, और इस तरह कोड का उपयोग करें: यदि (डिबग) cout << "..."; - मैक्रोज़ की कोई ज़रूरत नहीं!
स्टेफन मोनोव

@Stefan: वास्तव में, यह वही है जो अब मैं करता हूं। यदि कोई डिबग उस स्थिति में गलत है, तो कोई भी संकलक कोई कोड उत्पन्न नहीं करेगा।
मैथ्यू पैग

1

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

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