Click here to Skip to main content
15,881,882 members
Articles / Programming Languages / C++11
Tip/Trick

Macro Magic

Rate me:
Please Sign up or sign in to vote.
4.24/5 (6 votes)
5 Mar 2016CPOL 19K   125   11   10
Everything you always wanted to know about Macros but were afraid to ask

Introduction

Think macros are simple, boring and of little use, huh?

Background

C++ templates are not a replacement to the C macros, but rather combined together creates a powerful instrument, which allow experienced programmers to implement interesting idioms like Execute Member Function If It Is Present.

Using the Code

So, what we can do with macros?

  1. Multi line

    C++
    // Literally equal to the #define MIN_(A, B) ((A) < (B) ? (A) : (B))
    #define MIN_(A, B) (\
                        (A) < (B) ? \
                        (A) : (B)\
                       )
  2. Variadic

    C++
    // Using PRINT_ERROR_("%s they be stealin my %s!", "oh noes", "bucket")
    //  will print "oh noes they be stealin my bucket" in to the standard error stream
    #define PRINT_ERROR_(...) fprintf(stderr, __VA_ARGS__)
  3. Concatenation

    As strings:

    C++
    #define HELLO_ "say hello to my little"
    #define SPACE_ " "
    #define WORLD_ "friend"
    
    // Will be ptr. to the compile-time constant C str. "say hello to my little friend"
    static auto const HELLO_WORLD_ = HELLO_""SPACE_""WORLD_;

    As tokens:

    C++
    #define NUMBER_FROM_DIGITS_(D1, D2, D3) D1 ## D2 ## D3
    
    static const auto MY_NUMBER_ = NUMBER_FROM_DIGITS_(1, 2, 3); // will be 123
  4. Stringification

    C++
    #define MAKE_STR_(STR1, STR2, STR3) #STR1""#STR2""#STR3
    
    // Will be ptr. to the compile-time constant C str. "paint_it_black"
    static auto const MY_STR_ = MAKE_STR_(paint, _it_, black);
  5. Call other

    C++
    #define M_S_(arg) #arg // stringify
    #define MAKE_STR__(arg) M_S_(arg)
    
    // Will be ptr. to the compile-time constant C str.
    // In MS VS 2013: "+2,147,483,647" (for 32 bit)
    // In modern GCC: "INT_MAX"
    static auto const MY_STR__ = MAKE_STR__(INT_MAX);
  6. Function-like AND recursion

    C++
    int f() throw() {return 1;}
    
    // Only expanded if appears with parentheses
    #define f() (f() + 1) // self-reference is NOT considered a macro call (passed unchanged)
    
    static const auto VAL_1_ = f(); // will be 2
    
    static auto const VAL_2_ = f; // will ptr. to the function
  7. One definition rule

    C++
    #define SUM(A, B) ((A) + (B))
    #define SUM(A, B) ((A) + (B)) // NO compile error here [the rule doesn't applied to macros]
    
    #define SUM(A, B) ((A)+(B)) // compile warning here (allowed redefinition)
    
    #define SUM(A, B) (  (A) + (B)   )
    #define SUM(A, B) ( (A   ) + 
    	(   B) ) // NO compile warning here (if spacers, their amount is ignored)
    #define SUM(A, B) ( (A   ) /*what if*/ + 
    	/*add some comments here*/ (   B) ) // NO redefinition here: comments count as spacers
  8. Redefinition "on the fly"

    C++
    #define SUM(A, B) ((A) + (B))
    
    // Will be 1 + 3 + 2 = 6
    static const auto VAL_ = SUM(1
    #undef SUM
    #define SUM + 3
    SUM, // new definition is used for argument pre-expansion
    2);  // original definition is used for argument replacement

Tests

Test code in the Ideone online compiler

C++
std::cout << MIN_(1 + 2, 3 + 4) << std::endl;                   // prints "3"
PRINT_ERROR_("%s they be stealin my %s!", "oh noes", "bucket"); // "oh noes they be stealin my bucket!"
std::cout << HELLO_WORLD_ << std::endl;                         // "say hello to my little friend"
std::cout << MY_NUMBER_ + 1 << std::endl;                       // prints 124
std::cout << MY_STR_ << std::endl;                              // prints "paint_it_black"
std::cout << MY_STR__ << std::endl;                             // prints "INT_MAX"
std::cout << VAL_1_ << std::endl;                               // prints "2"
std::cout << VAL_2_ + 10 << std::endl;                          // prints "1" (as a non-nil pointer)
std::cout << VAL_ << std::endl;                                 // prints "6"

Points of Interest

Warning! The result may vary due to the compiler used!

Know more magic? Share in the comments!

History

  • 5th March, 2016: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) https://www.simbirsoft.com
Russian Federation Russian Federation
C/C++ dеvеlopеr (MS VS/WinAPI)

Comments and Discussions

 
Generalvery good summary! Pin
Southmountain26-Aug-17 8:35
Southmountain26-Aug-17 8:35 
QuestionC vs C++ Pin
degski7-Mar-16 18:50
degski7-Mar-16 18:50 
AnswerRe: C vs C++ Pin
Shvetsov Evgeniy7-Mar-16 23:47
professionalShvetsov Evgeniy7-Mar-16 23:47 
GeneralRe: C vs C++ Pin
degski8-Mar-16 20:10
degski8-Mar-16 20:10 
GeneralRe: C vs C++ Pin
Shvetsov Evgeniy9-Mar-16 1:21
professionalShvetsov Evgeniy9-Mar-16 1:21 
AnswerRe: C vs C++ Pin
Ramesh Sharma 202122-Jun-21 4:47
Ramesh Sharma 202122-Jun-21 4:47 
QuestionYou are advertising using undefined behavior. Pin
Member 123764117-Mar-16 17:59
Member 123764117-Mar-16 17:59 
AnswerRe: You are advertising using undefined behavior. Pin
Shvetsov Evgeniy7-Mar-16 23:36
professionalShvetsov Evgeniy7-Mar-16 23:36 
SuggestionMacros with multiple statements Pin
Member 113066197-Mar-16 11:15
Member 113066197-Mar-16 11:15 
GeneralRe: Macros with multiple statements Pin
Shvetsov Evgeniy7-Mar-16 23:30
professionalShvetsov Evgeniy7-Mar-16 23:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.