Thread: Macro magic

  1. #1
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937

    Macro magic

    Sorry about all of the no-impending-doom code-practice-centered questions lately. I figure there's no better place to ask. The computer science guys don't talk to us physicists on campus (I think we've abused them enough).

    I've always learned that, in C++, using macros (and hiding code in a non-type-safe way in general) is evil. However, I've come up with a little short hand that seems innocuous. Please show me how this macro could be dangerous, and/or propose a better solution.
    Code:
    #define THE_DEBUG_STREAM std::cout
    #ifndef NDEBUG
        #define PRINT_TO_DEBUG_STREAM( x ) { (THE_DEBUG_STREAM) << "{ " << (#x) << " }: " << (x) << '\n'; }
    #else
        #define PRINT_TO_DEBUG_STREAM( x ) { (x); }
    #endif
    #define printdb PRINT_TO_DEBUG_STREAM
    Ex:
    Code:
    int function()
    {
         return 17;
    }
    
    int main()
    {
        int variable; 
        printdb(variable = function());
    }
    Output:
    Code:
    { variable = function() }: 17
    The only issue I could think of is all of the pieces of code like this
    Code:
    some_variable;
    that would be littered throughout my program ifdef NDEBUG..... but that's skipped over, right?
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    EDIT:
    Oops, I made a mistake by testing in the wrong order.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    I think variable would be assigned 17 in either case, since
    Code:
    //if NDEBUG is defined
    #define PRINT_TO_DEBUG_STREAM( x ) { (x) };
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    But I think that's why the Monkey defined it the way he did -- if NDEBUG is defined, the statement still happens, so variable is 17. (That's why you can go wrong with assert.)

    There's situations where you can't introduce braces -- somebody recently tried to do that in a ternary operator and that didn't go well at all. That's not dangerous per se, it just doesn't work.

  5. #5
    Banned
    Join Date
    Jan 2009
    Posts
    30
    The reason the computer science guys may say its evil is that because in C++ you always have the option of creating inline functions.

    Code:
    #ifndef NDEBUG
        template<typename T>
        void debug_output_function(std::ostream &stream, const T &x, const char *name)
        {
           stream << "{" << name << "};" << x << std::endl;
        }
        #define PRINT_TO_DEBUG_STREAM( x ) debug_output_function(THE_DEBUG_STREAM, x, (#x))
    #else
        #define PRINT_TO_DEBUG_STREAM( x )
    #endif

  6. #6
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Firstly, don't put code that does something (has side-effects) into macros that are not executed in release.

    Secondly, std::cerr might be more suitable for debug output (for example, it is flushed automatically, so you should see all the output that you have printed in case of crash).

    Thirdly, to compile the macro to nothing you can use:
    Code:
        #define PRINT_TO_DEBUG_STREAM( x ) (void(0))
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  7. #7
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    That does look nicer, sphynxter. And thanks for the heads up, tabstop.

    *edit* And thank you, anon, but I must stress that I don't want the code to do nothing if NDEBUG, I just want it not to print anything.

    Thanks again.
    Last edited by CodeMonkey; 01-14-2009 at 02:33 PM.
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by CodeMonkey View Post
    That does look nicer, sphynxter. And thanks for the heads up, tabstop.

    *edit* And thank you, anon, but I must stress that I don't want the code to do nothing if NDEBUG, I just want it not to print anything.

    Thanks again.
    Having a macro that "debug prints" something and actually evaluates its argument even when disabled sounds like a good recipe for confusing the crap out of people.

    "I took that line out because all it's doing is printing a diagnostic."

    "No, that line keeps the life support systems running."

    "Then why is it called DEBUG PRINT?"
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  9. #9
    Banned
    Join Date
    Jan 2009
    Posts
    30
    Typically one would be printing debug info to std::cerr, but I suppose this is just adding on to brewbuck's previous statement.

  10. #10
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    Point well made.
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  11. #11
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by brewbuck View Post
    Having a macro that "debug prints" something and actually evaluates its argument even when disabled sounds like a good recipe for confusing the crap out of people.

    "I took that line out because all it's doing is printing a diagnostic."

    "No, that line keeps the life support systems running."

    "Then why is it called DEBUG PRINT?"
    Yes. We had a case of something along those lines in one of our test-platforms:
    Code:
    debug_print("Doing %d\n", x++);
    Someone was annoyed that this code produced 8000 lines of output in one test, so took the line out. Unfortunately, that meant that x++ got removed too, which mean that a bunch of OTHER tests, that relied on x being "which test to run next" didn't get updated, and x never reached the value of "all tests done". Some tests were using their own counter, so it didn't matter, but for others, it was critical.

    Debug statement should be removable without ANY side effect to the actual funciton of the code.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem building Quake source
    By Silvercord in forum Game Programming
    Replies: 16
    Last Post: 07-11-2010, 09:13 AM
  2. Errors including <windows.h>
    By jw232 in forum Windows Programming
    Replies: 4
    Last Post: 07-29-2008, 01:29 PM
  3. Quantum Random Bit Generator
    By shawnt in forum C++ Programming
    Replies: 62
    Last Post: 06-18-2008, 10:17 AM
  4. help on magic square
    By katway in forum C Programming
    Replies: 2
    Last Post: 03-07-2005, 06:44 PM
  5. Magic Squares!
    By ZAM777 in forum C++ Programming
    Replies: 1
    Last Post: 04-28-2004, 03:34 PM