खोज…


परिचय

C प्रीप्रोसेसर एक सरल टेक्स्ट पार्सर / प्रतिकृति है जो कोड के वास्तविक संकलन से पहले चलाया जाता है। C (और बाद में C ++) भाषा के उपयोग को बढ़ाने और आसान बनाने के लिए इसका उपयोग किया जा सकता है:

ए। #Include का उपयोग करके अन्य फाइलें भी #include

ख। #define का उपयोग करके एक टेक्स्ट-प्रतिस्थापन मैक्रो को #define

सी। #if #ifdef का उपयोग करके सशर्त संकलन

घ। प्लेटफ़ॉर्म / कंपाइलर विशिष्ट तर्क (सशर्त संकलन का विस्तार)

टिप्पणियों

आपकी स्रोत फ़ाइलों को कंपाइलर को सौंपने से पहले प्रीप्रोसेसर कथनों को निष्पादित किया जाता है। वे बहुत कम स्तर के सशर्त तर्क के लिए सक्षम हैं। चूंकि प्रीप्रोसेसर निर्माण (जैसे ऑब्जेक्ट-जैसे मैक्रोज़) सामान्य कार्यों की तरह टाइप नहीं किए जाते हैं (संकलन से पहले प्रीप्रोसेसिंग चरण होता है) कंपाइलर प्रकार की जांच लागू नहीं कर सकते हैं, इसलिए उन्हें सावधानी से उपयोग किया जाना चाहिए।

गार्ड शामिल करें

एक हेडर फ़ाइल को अन्य हेडर फ़ाइलों द्वारा शामिल किया जा सकता है। एक स्रोत फ़ाइल (संकलन इकाई) जिसमें कई हेडर शामिल हैं, इसलिए, अप्रत्यक्ष रूप से, कुछ हेडर को एक से अधिक बार शामिल कर सकते हैं। यदि ऐसी हेडर फ़ाइल जिसे एक से अधिक बार शामिल किया गया है, जिसमें परिभाषाएँ शामिल हैं, तो कंपाइलर (प्रीप्रोसेसिंग के बाद) एक परिभाषा नियम (2003 C ++ मानक के §3.2) का उल्लंघन का पता लगाता है और इसलिए एक नैदानिक और संकलन विफल रहता है।

एकाधिक समावेशन को "गार्ड शामिल करें" का उपयोग करने से रोका जाता है, जिन्हें कभी-कभी हेडर गार्ड या मैक्रो गार्ड के रूप में भी जाना जाता है। इन्हें प्रीप्रोसेसर #define , #ifndef , #endif निर्देशों का उपयोग करके लागू किया जाता है।

जैसे

// Foo.h
#ifndef FOO_H_INCLUDED 
#define FOO_H_INCLUDED

class Foo    //  a class definition
{
};

#endif

गार्ड्स का उपयोग करने का मुख्य लाभ यह है कि वे सभी मानक-अनुरूप कंपाइलर और प्रीप्रोसेसर के साथ काम करेंगे।

हालाँकि, गार्ड को शामिल करना भी डेवलपर्स के लिए कुछ समस्याएँ पैदा करता है, क्योंकि यह सुनिश्चित करना आवश्यक है कि किसी प्रोजेक्ट में उपयोग किए जाने वाले सभी हेडर के भीतर मैक्रोज़ अद्वितीय हैं। विशेष रूप से, यदि दो (या अधिक) हेडर FOO_H_INCLUDED उपयोग FOO_H_INCLUDED क्योंकि उनके शामिल गार्ड होते हैं, तो संकलन इकाई में शामिल उन हेडर में से पहला प्रभावी रूप से दूसरों को शामिल करने से रोक देगा। विशेष रूप से चुनौतियों का सामना किया जाता है यदि कोई परियोजना कई तृतीय-पक्ष पुस्तकालयों का उपयोग करता है हेडर फ़ाइलों के साथ जो कि उपयोग करने के लिए होता है, जिसमें सामान्य रूप से गार्ड शामिल होते हैं।

यह सुनिश्चित करने के लिए भी आवश्यक है कि शामिल गार्ड में प्रयुक्त मैक्रोज़ हेडर फ़ाइलों में परिभाषित किसी भी अन्य मैक्रोज़ के साथ संघर्ष न करें।

अधिकांश C ++ कार्यान्वयन भी #pragma once निर्देश का समर्थन करते हैं जो सुनिश्चित करता है कि फ़ाइल केवल एक बार संकलन के भीतर ही शामिल हो। यह एक वास्तविक मानक निर्देश है, लेकिन यह किसी भी आईएसओ C ++ मानक का हिस्सा नहीं है। उदाहरण के लिए:

// Foo.h
#pragma once

class Foo
{
};

जबकि #pragma once गार्ड से जुड़ी कुछ समस्याओं से बचा जाता है, मानकों में परिभाषा के अनुसार एक #pragma - स्वाभाविक रूप से एक कंपाइलर-विशिष्ट हुक है, और इसे संकलक द्वारा अनदेखा किया जाएगा जो इसका समर्थन नहीं करते हैं। जो परियोजनाएं #pragma once उपयोग करती हैं, वे उन #pragma once को पोर्ट करना अधिक कठिन हैं जो इसका समर्थन नहीं करते हैं।

C ++ के लिए कई कोडिंग दिशानिर्देश और आश्वासन मानक विशेष रूप से #include हैडर फ़ाइलों के अलावा या हेडर में गार्ड शामिल करने के लिए पूर्वप्रोसेसर के किसी भी उपयोग को हतोत्साहित करते हैं।

सशर्त तर्क और क्रॉस-प्लेटफ़ॉर्म हैंडलिंग

संक्षेप में, सशर्त पूर्व-प्रसंस्करण तर्क मैक्रो-परिभाषाओं का उपयोग करके संकलन के लिए कोड-लॉजिक को उपलब्ध या अनुपलब्ध बनाने के बारे में है।

तीन प्रमुख उपयोग-मामले हैं:

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

उदाहरण: फ़ाइलों को हटाने के लिए एक क्रॉस-प्लेटफ़ॉर्म दृष्टिकोण (चित्रण):

#ifdef _WIN32
#include <windows.h> // and other windows system files
#endif
#include <cstdio>

bool remove_file(const std::string &path) 
{
#ifdef _WIN32
  return DeleteFile(path.c_str());
#elif defined(_POSIX_VERSION) || defined(__unix__)
  return (0 == remove(path.c_str()));
#elif defined(__APPLE__)
  //TODO: check if NSAPI has a more specific function with permission dialog
  return (0 == remove(path.c_str()));
#else 
#error "This platform is not supported"
#endif
}

मैक्रोज़ जैसे _WIN32 , __APPLE__ या __unix__ आमतौर पर इसी कार्यान्वयन द्वारा पूर्वनिर्धारित होते हैं।

उदाहरण b: डीबग बिल्ड के लिए अतिरिक्त लॉगिंग सक्षम करना:

void s_PrintAppStateOnUserPrompt()
{
    std::cout << "--------BEGIN-DUMP---------------\n"
              << AppState::Instance()->Settings().ToString() << "\n"
#if ( 1 == TESTING_MODE ) //privacy: we want user details only when testing
              << ListToString(AppState::UndoStack()->GetActionNames())
              << AppState::Instance()->CrntDocument().Name() 
              << AppState::Instance()->CrntDocument().SignatureSHA() << "\n"
#endif
              << "--------END-DUMP---------------\n"
}

उदाहरण c: एक अलग उत्पाद बिल्ड में एक प्रीमियम सुविधा सक्षम करें (नोट: यह उदाहरण के लिए है। यह अक्सर एक बेहतर तरीका है कि किसी एप्लिकेशन को पुनः इंस्टॉल करने की आवश्यकता के बिना किसी सुविधा को अनलॉक करने की अनुमति दें)

void MainWindow::OnProcessButtonClick()
{
#ifndef _PREMIUM
    CreatePurchaseDialog("Buy App Premium", "This feature is available for our App Premium users. Click the Buy button to purchase the Premium version at our website");
    return;
#endif
    //...actual feature logic here
}

कुछ सामान्य ट्रिक्स:

आह्वान समय पर प्रतीकों को परिभाषित करना:

प्रीप्रोसेसर को पूर्वनिर्धारित प्रतीकों (वैकल्पिक आरंभीकरण के साथ) के साथ कहा जा सकता है। उदाहरण के लिए यह कमांड ( gcc -E केवल प्रीप्रोसेसर चलाता है)

gcc -E -DOPTIMISE_FOR_OS_X -DTESTING_MODE=1 Sample.cpp

Sample.cpp को उसी तरह से प्रोसेस करता है जैसे कि अगर #define OPTIMISE_FOR_OS_X और #define TESTING_MODE 1 को नमूना.cpp के शीर्ष पर जोड़ा गया।

मैक्रो को परिभाषित करना परिभाषित किया गया है:

यदि कोई मैक्रो परिभाषित नहीं है और उसके मूल्य की तुलना या जाँच की जाती है, तो प्रीप्रोसेसर लगभग हमेशा मान को 0 मानता है। इसके साथ काम करने के कुछ तरीके हैं। एक दृष्टिकोण यह मान लेना है कि डिफ़ॉल्ट सेटिंग्स 0 के रूप में प्रस्तुत की जाती हैं, और किसी भी परिवर्तन (जैसे ऐप बिल्ड प्रोफ़ाइल) को स्पष्ट रूप से करने की आवश्यकता है (उदाहरण के लिए ENABLE_EXTRA_DEBUGGING = 0 डिफ़ॉल्ट रूप से, सेट -DENABLE_EXTRA_DEBUGGING = 1 ओवरराइड करने के लिए)। एक और दृष्टिकोण सभी परिभाषाओं और चूक को स्पष्ट करता है। इसे #ifndef और #error निर्देशों के संयोजन का उपयोग करके प्राप्त किया जा सकता है:

#ifndef (ENABLE_EXTRA_DEBUGGING)
// please include DefaultDefines.h if not already included.
#    error "ENABLE_EXTRA_DEBUGGING is not defined"
#else
#    if ( 1 == ENABLE_EXTRA_DEBUGGING )
  //code
#    endif
#endif

मैक्रो

मैक्रोज़ को दो मुख्य समूहों में वर्गीकृत किया गया है: ऑब्जेक्ट-जैसे मैक्रोज़ और फ़ंक्शन-जैसे मैक्रोज़। मैक्रोज़ को संकलन प्रक्रिया के प्रारंभ में टोकन प्रतिस्थापन के रूप में माना जाता है। इसका मतलब यह है कि कोड के बड़े (या दोहराए जाने वाले) वर्गों को प्रीप्रोसेसर मैक्रो में सार किया जा सकता है।

// This is an object-like macro
#define    PI         3.14159265358979

// This is a function-like macro.
// Note that we can use previously defined macros
// in other macro definitions (object-like or function-like)
// But watch out, its quite useful if you know what you're doing, but the
// Compiler doesnt know which type to handle, so using inline functions instead
// is quite recommended (But e.g. for Minimum/Maximum functions it is quite useful)
#define    AREA(r)    (PI*(r)*(r))

// They can be used like this:
double pi_macro   = PI;
double area_macro = AREA(4.6);

क्यूटी पुस्तकालय इस तकनीक का उपयोग करता है ताकि मेटा-ऑब्जेक्ट सिस्टम बनाने के लिए उपयोगकर्ता घोषित कर सके Q_OBJECT मैक्रो को उपयोगकर्ता परिभाषित वर्ग के प्रमुख पर QObject बढ़ाता है।

मैक्रो नाम आमतौर पर सभी कैप्स में लिखे जाते हैं, जिससे उन्हें सामान्य कोड से अंतर करना आसान हो जाता है। यह एक आवश्यकता नहीं है, लेकिन केवल कई प्रोग्रामर द्वारा अच्छी शैली मानी जाती है।


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

double pi_squared = PI * PI;
// Compiler sees:
double pi_squared = 3.14159265358979 * 3.14159265358979;

double area = AREA(5);
// Compiler sees:
double area = (3.14159265358979*(5)*(5))

इसके कारण, फ़ंक्शन-जैसे मैक्रो पैरामीटर अक्सर कोष्ठक के भीतर संलग्न होते हैं, जैसा कि ऊपर AREA() है। यह किसी भी कीड़े को रोकने के लिए है जो मैक्रो के विस्तार के दौरान हो सकता है, विशेष रूप से एकल मैक्रो पैरामीटर के कारण कई वास्तविक मूल्यों से बना होता है।

#define BAD_AREA(r) PI * r * r

double bad_area = BAD_AREA(5 + 1.6);
// Compiler sees:
double bad_area = 3.14159265358979 * 5 + 1.6 * 5 + 1.6;

double good_area = AREA(5 + 1.6);
// Compiler sees:
double good_area = (3.14159265358979*(5 + 1.6)*(5 + 1.6));

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

int oops = 5;
double incremental_damage = AREA(oops++);
// Compiler sees:
double incremental_damage = (3.14159265358979*(oops++)*(oops++));

इसके अतिरिक्त, मैक्रोज़ कोई प्रकार-सुरक्षा प्रदान नहीं करते हैं, जिससे टाइप बेमेल के बारे में कठिन-से-समझने में त्रुटि होती है।


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

#define IF_BREAKER(Func) Func();

if (some_condition)
    // Oops.
    IF_BREAKER(some_func);
else
    std::cout << "I am accidentally an orphan." << std::endl;

इस उदाहरण में, अनजाने में डबल अर्धविराम टूट जाता है if...else ब्लॉक, संकलक को else से मिलान करने से रोकता है if । इसे रोकने के लिए, अर्धविराम को मैक्रो परिभाषा से छोड़ा गया है, जो इसे इसके किसी भी उपयोग के तुरंत बाद अर्धविराम को "निगल" करने का कारण होगा।

#define IF_FIXER(Func) Func()

if (some_condition)
    IF_FIXER(some_func);
else
    std::cout << "Hooray!  I work again!" << std::endl;

अनुगामी अर्धविराम को छोड़ने से मैक्रो को वर्तमान कथन को समाप्त किए बिना उपयोग करने की अनुमति मिलती है, जो फायदेमंद हो सकता है।

#define DO_SOMETHING(Func, Param) Func(Param, 2)

// ...

some_function(DO_SOMETHING(some_func, 3), DO_SOMETHING(some_func, 42));

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

#define TEXT "I \
am \
many \
lines."

// ...

std::cout << TEXT << std::endl; // Output:   I am many lines.

यह विशेष रूप से जटिल फ़ंक्शन-जैसे मैक्रोज़ में उपयोगी है, जिसे कई लाइनों को कवर करने की आवश्यकता हो सकती है।

#define CREATE_OUTPUT_AND_DELETE(Str) \
    std::string* tmp = new std::string(Str); \
    std::cout << *tmp << std::endl; \
    delete tmp;

// ...

CREATE_OUTPUT_AND_DELETE("There's no real need for this to use 'new'.")

अधिक जटिल फ़ंक्शन-जैसे मैक्रोज़ के मामले में, संभावित नाम टकरावों को रोकने के लिए या वास्तविक फ़ंक्शन के समान मैक्रो के अंत में ऑब्जेक्ट को नष्ट करने के लिए उन्हें अपने स्वयं के दायरे देने के लिए उपयोगी हो सकता है। इसके लिए एक सामान्य मुहावरा 0 है , जहां मैक्रो को डू- ब्लॉक में संलग्न किया गया है। इस ब्लॉक का आमतौर पर अर्धविराम के साथ पालन नहीं किया जाता है, जिससे यह अर्धविराम को निगल सकता है।

#define DO_STUFF(Type, Param, ReturnVar) do { \
    Type temp(some_setup_values); \
    ReturnVar = temp.process(Param); \
} while (0)

int x;
DO_STUFF(MyClass, 41153.7, x);

// Compiler sees:

int x;
do {
    MyClass temp(some_setup_values);
    x = temp.process(41153.7);
} while (0);

वेरिक मैक्रोज़ भी हैं; वैरडीकल फंक्शंस के समान, ये एक वेरिएबल नंबर ले लेते हैं, और फिर इन सभी को एक विशेष "वरार्ग्स" पैरामीटर, __VA_ARGS__

#define VARIADIC(Param, ...) Param(__VA_ARGS__)

VARIADIC(printf, "%d", 8);
// Compiler sees:
printf("%d", 8);

ध्यान दें कि विस्तार के दौरान, __VA_ARGS__ को परिभाषा में कहीं भी रखा जा सकता है, और इसे सही ढंग से विस्तारित किया जाएगा।

#define VARIADIC2(POne, PTwo, PThree, ...) POne(PThree, __VA_ARGS__, PTwo)

VARIADIC2(some_func, 3, 8, 6, 9);
// Compiler sees:
some_func(8, 6, 9, 3);

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

// In this example, COMPILER is a user-defined macro specifying the compiler being used.

#if       COMPILER == "VS"
    #define VARIADIC3(Name, Param, ...) Name(Param, __VA_ARGS__)
#elif     COMPILER == "GCC"
    #define VARIADIC3(Name, Param, ...) Name(Param, ##__VA_ARGS__)
#endif /* COMPILER */

प्रीप्रोसेसर त्रुटि संदेश

प्रीप्रोसेसर का उपयोग करके संकलन त्रुटियों को उत्पन्न किया जा सकता है। यह कई कारणों से उपयोगी है जिनमें से कुछ में उपयोगकर्ता को सूचित करना, यदि वे असमर्थित प्लेटफॉर्म या असमर्थित कंपाइलर पर हैं।

उदाहरण के लिए वापसी त्रुटि अगर gcc संस्करण 3.0.0 या उससे पहले का है।

#if __GNUC__ < 3
#error "This code requires gcc > 3.0.0"
#endif

उदाहरण के लिए, Apple कंप्यूटर पर कंपाइल करने पर रिटर्न एरर।

#ifdef __APPLE__
#error "Apple products are not supported in this release"
#endif

पूर्वनिर्धारित मैक्रों

पूर्वनिर्धारित मैक्रोज़ वे हैं जो कंपाइलर परिभाषित करता है (स्रोत फ़ाइल में उन उपयोगकर्ता के विपरीत)। उन मैक्रो को उपयोगकर्ता द्वारा फिर से परिभाषित या अपरिभाषित नहीं किया जाना चाहिए।

निम्नलिखित मैक्रो C ++ मानक द्वारा पूर्वनिर्धारित हैं:

  • __LINE__ में उस मैक्रो लाइन का लाइन नंबर होता है जिसका उपयोग किया जाता है, और इसे #line निर्देश द्वारा बदला जा सकता है।
  • __FILE__ में उस फ़ाइल का फ़ाइल नाम है जिसका उपयोग इस मैक्रो में किया गया है और इसे #line निर्देश द्वारा बदला जा सकता है।
  • __DATE__ में फ़ाइल संकलन की तिथि ( "Mmm dd yyyy" प्रारूप) समाहित है, जहाँ MD को प्रारूपित किया जाता है जैसे कि कॉल करने के लिए std::asctime()
  • फ़ाइल संकलन में __TIME__ में समय ( "hh:mm:ss" प्रारूप) होता है।
  • __cplusplus C ++ फ़ाइलों को संकलित करते समय (अनुरूप) C ++ कंपाइलर द्वारा परिभाषित किया गया है। अपने मूल्य संकलक के साथ पूरी तरह अनुरूप है मानक संस्करण है, यानी 199711L सी ++ 98 और सी ++ 03, के लिए 201103L सी के लिए ++ 11 और 201402L सी ++ 14 मानक के लिए।
c ++ 11
  • __STDC_HOSTED__ को 1 को परिभाषित किया गया है यदि कार्यान्वयन होस्ट किया गया है , या 0 अगर यह फ्रीस्टैंडिंग है
c ++ 17
  • __STDCPP_DEFAULT_NEW_ALIGNMENT__ एक शामिल size_t शाब्दिक जो संरेखण-अनजान के लिए एक कॉल के लिए इस्तेमाल किया संरेखण है, operator new

इसके अतिरिक्त, निम्नलिखित मैक्रोज़ को कार्यान्वयन द्वारा पूर्वनिर्धारित करने की अनुमति दी जाती है, और मौजूद नहीं हो सकती है:

  • __STDC__ का कार्यान्वयन-निर्भर अर्थ है, और आमतौर पर केवल तब परिभाषित किया जाता है जब किसी फ़ाइल को C के रूप में संकलित किया जाता है, पूर्ण C मानक अनुपालन को दर्शाने के लिए। (या कभी नहीं, यदि कंपाइलर इस मैक्रो का समर्थन नहीं करने का फैसला करता है।)
c ++ 11
  • __STDC_VERSION__ का कार्यान्वयन-निर्भर अर्थ है, और इसका मान आमतौर पर C संस्करण है, इसी तरह __cplusplus C ++ संस्करण कैसे है। (या परिभाषित भी नहीं किया गया है, यदि कंपाइलर इस मैक्रो का समर्थन नहीं करने का फैसला करता है।)
  • __STDC_MB_MIGHT_NEQ_WC__ को 1 में परिभाषित किया गया है, यदि मूल वर्ण सेट के संकीर्ण एन्कोडिंग के मान उनके व्यापक समकक्षों के मान के बराबर नहीं हो सकते हैं (जैसे कि (uintmax_t)'x' != (uintmax_t)L'x' );
  • __STDC_ISO_10646__ को परिभाषित किया गया है यदि wchar_t को यूनिकोड के रूप में एन्कोड किया गया है, और फॉर्म yyyymmL में एक पूर्णांक स्थिरांक तक विस्तारित होता है, जो नवीनतम यूनिकोड संशोधन का समर्थन करता है।
  • __STDCPP_STRICT_POINTER_SAFETY__ को 1 को परिभाषित किया गया है, यदि कार्यान्वयन में सख्त पॉइंटर सुरक्षा है (अन्यथा इसमें पॉइंटर पॉइंटर सेफ्टी है )
  • __STDCPP_THREADS__ को 1 से परिभाषित किया गया है, अगर कार्यक्रम में निष्पादन का एक से अधिक धागा हो सकता है ( कार्यान्वयन को फ्रीस्टैंडिंग पर लागू किया जा सकता है - होस्ट किए गए कार्यान्वयन हमेशा एक से अधिक थ्रेड हो सकते हैं)

यह __func__ उल्लेख करने योग्य भी है, जो एक मैक्रो नहीं है, लेकिन एक पूर्वनिर्धारित फ़ंक्शन-स्थानीय चर है। इसमें उस फ़ंक्शन का नाम होता है जिसका उपयोग कार्यान्वयन-परिभाषित प्रारूप में एक स्थिर चरित्र सरणी के रूप में किया जाता है।

उन मानक पूर्वनिर्धारित मैक्रोज़ के शीर्ष पर, कंपाइलरों के पास पूर्वनिर्धारित मैक्रोज़ का अपना सेट हो सकता है। उन लोगों को सीखने के लिए संकलक प्रलेखन का उल्लेख करना चाहिए। उदाहरण के लिए:

मैक्रोज़ में से कुछ सिर्फ कुछ फ़ीचर के समर्थन के लिए हैं:

#ifdef __cplusplus // if compiled by C++ compiler
extern "C"{ // C code has to be decorated
   // C library header declarations here
}
#endif

अन्य डीबगिंग के लिए बहुत उपयोगी हैं:

c ++ 11
bool success = doSomething( /*some arguments*/ );
if( !success ){
    std::cerr << "ERROR: doSomething() failed on line " << __LINE__ - 2
              << " in function " << __func__ << "()"
              << " in file " << __FILE__
              << std::endl;
}

और अन्य तुच्छ संस्करण नियंत्रण के लिए:

int main( int argc, char *argv[] ){
    if( argc == 2 && std::string( argv[1] ) == "-v" ){
        std::cout << "Hello World program\n"
                  << "v 1.1\n" // I have to remember to update this manually
                  << "compiled: " << __DATE__ << ' ' << __TIME__ // this updates automagically
                  << std::endl;
    }
    else{
        std::cout << "Hello World!\n";
    }
}

एक्स-मैक्रो

संकलन समय पर कोड संरचनाओं को उत्पन्न करने के लिए एक मुहावरेदार तकनीक।

एक एक्स-मैक्रो में दो भाग होते हैं: सूची, और सूची का निष्पादन।

उदाहरण:

#define LIST \
    X(dog)   \
    X(cat)   \
    X(racoon)

// class Animal {
//  public:
//    void say();
// };

#define X(name) Animal name;
LIST
#undef X

int main() {
#define X(name) name.say();
    LIST
#undef X

    return 0;
}

जिसका प्रसार प्रीप्रोसेसर द्वारा निम्नलिखित में किया जाता है:

Animal dog;
Animal cat;
Animal racoon;

int main() {
    dog.say();
    cat.say();
    racoon.say();

    return 0;
}    

जैसे-जैसे सूचियां बड़ी होती जाती हैं (मान लीजिए कि, 100 से अधिक तत्व हैं), यह तकनीक अत्यधिक कॉपी-पेस्टिंग से बचने में मदद करती है।

स्रोत: https://en.wikipedia.org/wiki/X_Macro

इसे भी देखें: X-macros


यदि LIST का उपयोग करने से पहले सीमली अप्रासंगिक X को परिभाषित करना आपकी पसंद के अनुसार नहीं है, तो आप एक मैक्रो नाम को एक तर्क के रूप में पारित कर सकते हैं:

#define LIST(MACRO) \
    MACRO(dog) \
    MACRO(cat) \
    MACRO(racoon)

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

#define FORWARD_DECLARE_ANIMAL(name) Animal name;
LIST(FORWARD_DECLARE_ANIMAL)

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

//a walkaround for Visual studio
#define EXPAND(x) x

#define LIST(MACRO, ...) \
    EXPAND(MACRO(dog, __VA_ARGS__)) \
    EXPAND(MACRO(cat, __VA_ARGS__)) \
    EXPAND(MACRO(racoon, __VA_ARGS__))

पहला तर्क द्वारा आपूर्ति की है LIST , जबकि बाकी में उपयोगकर्ता द्वारा प्रदान की गई LIST मंगलाचरण। उदाहरण के लिए:

#define FORWARD_DECLARE(name, type, prefix) type prefix##name;
LIST(FORWARD_DECLARE,Animal,anim_)
LIST(FORWARD_DECLARE,Object,obj_)

तक विस्तार होगा

Animal anim_dog;
Animal anim_cat;
Animal anim_racoon;
Object obj_dog;
Object obj_cat;
Object obj_racoon;        

#pragma एक बार

अधिकांश, लेकिन सभी नहीं, C ++ कार्यान्वयन #pragma once निर्देश को #pragma once समर्थन करते हैं जो सुनिश्चित करता है कि फ़ाइल केवल एक बार एक संकलन के भीतर शामिल हो। यह किसी भी आईएसओ C ++ मानक का हिस्सा नहीं है। उदाहरण के लिए:

// Foo.h
#pragma once

class Foo
{
};

जबकि #pragma once गार्ड से जुड़ी कुछ समस्याओं से बचा जाता है, मानकों में परिभाषा के अनुसार एक #pragma - स्वाभाविक रूप से एक कंपाइलर-विशिष्ट हुक है, और इसे संकलक द्वारा अनदेखा किया जाएगा जो इसका समर्थन नहीं करते हैं। जो परियोजनाएं #pragma once उपयोग करती हैं, उन्हें मानक-अनुरूप होने के लिए संशोधित किया जाना चाहिए।

कुछ संकलकों के साथ - विशेष रूप से वे जो पहले से तैयार हेडर को नियोजित करते हैं - #pragma once संकलन प्रक्रिया के काफी गति में परिणाम कर सकते हैं। इसी तरह, कुछ प्रीप्रोसेसरों ने ट्रैक करके संकलन का गति प्राप्त किया है जिसमें हेडर ने नियोजित किया है जिसमें गार्ड शामिल हैं। शुद्ध लाभ, जब दोनों #pragma once और गार्ड शामिल होते हैं, कार्यान्वयन पर निर्भर करता है और संकलन समय की वृद्धि या कमी हो सकती है।

#pragma once शामिल करने के लिए गार्ड को शामिल किया गया था, जब हेडर फ़ाइलों के लिए विंडोज़ पर MFC आधारित एप्लिकेशन लिखते हैं, और विजुअल स्टूडियो के add class द्वारा उत्पन्न किया गया था, add dialog add windows , add windows विजार्ड add windows । इसलिए उन्हें C ++ विंडोज आवेदकों में संयुक्त रूप से ढूंढना बहुत आम है।

प्रीप्रोसेसर ऑपरेटर

# मैक्रो पैरामीटर को स्ट्रिंग शाब्दिक में बदलने के लिए ऑपरेटर या स्ट्रिंगिंग ऑपरेटर का उपयोग किया जाता है। इसका उपयोग केवल मैक्रोज़ के तर्क के साथ किया जा सकता है।

// preprocessor will convert the parameter x to the string literal x
#define PRINT(x) printf(#x "\n")

PRINT(This line will be converted to string by preprocessor);
// Compiler sees
printf("This line will be converted to string by preprocessor""\n");

कंपाइलर दो स्ट्रिंग्स को समेटता है और अंतिम printf() तर्क एक स्ट्रिंग शाब्दिक होगा जिसके अंत में न्यूलाइन वर्ण होता है।

प्रीप्रोसेसर मैक्रो तर्क से पहले या बाद में रिक्त स्थान की उपेक्षा करेगा। तो नीचे प्रिंट स्टेटमेंट हमें वही परिणाम देगा।

PRINT(   This line will be converted to string by preprocessor );

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

PRINT(This "line" will be converted to "string" by preprocessor); 
// Compiler sees
printf("This \"line\" will be converted to \"string\" by preprocessor""\n");

## ऑपरेटर या टोकन चिपकाने वाले ऑपरेटर का उपयोग मैक्रो के दो मापदंडों या टोकन को व्यवस्थित करने के लिए किया जाता है।

// preprocessor will combine the variable and the x
#define PRINT(x) printf("variable" #x " = %d", variable##x)

int variableY = 15;
PRINT(Y);
//compiler sees
printf("variable""Y"" = %d", variableY);

और अंतिम आउटपुट होगा

variableY = 15


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow