Custom ASSERT macro

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Stephen Tyndall

    Custom ASSERT macro

    I know the preprocessor is evil, but I'd like to know what's going on in the
    following code.

    The problem is when the num variable is used in the ASSERT macro inside
    main(). When running the code, I get the following error from Visual
    C++.NET 2003:

    warning C4806: '==' : unsafe operation: no value of type 'bool' promoted to
    type 'int' can equal the given constant

    #define DEBUG 2

    #include <iostream>

    using namespace std;

    #if DEBUG == 0

    #define ASSERT(n)

    #elif DEBUG == 1

    #define ASSERT(n) if(!n) { cout << #n << " failed" << endl; }

    #elif DEBUG == 2

    #define ASSERT(n) \

    if(!n) { \

    cout << #n << " failed on line " << __LINE__ << endl; \

    } \

    else { \

    cout << #n << " passed on line " << __LINE__ << endl; \

    }

    #endif

    int main() {

    bool flag = true;

    int num = 5;

    ASSERT(flag == true);

    ASSERT(flag == false);

    // when I change the below to ASSERT((num == 5)); it works perfectly.

    // what's wrong with the version below?

    ASSERT(num == 5);

    return 0;

    }

    Thanks in advance for your help.


  • Artie Gold

    #2
    Re: Custom ASSERT macro

    Stephen Tyndall wrote:[color=blue]
    > I know the preprocessor is evil, but I'd like to know what's going on in the
    > following code.
    >
    > The problem is when the num variable is used in the ASSERT macro inside
    > main(). When running the code, I get the following error from Visual
    > C++.NET 2003:
    >
    > warning C4806: '==' : unsafe operation: no value of type 'bool' promoted to
    > type 'int' can equal the given constant
    >
    > #define DEBUG 2
    >
    > #include <iostream>
    >
    > using namespace std;
    >
    > #if DEBUG == 0
    >
    > #define ASSERT(n)
    >
    > #elif DEBUG == 1
    >
    > #define ASSERT(n) if(!n) { cout << #n << " failed" << endl; }
    >
    > #elif DEBUG == 2
    >
    > #define ASSERT(n) \
    >
    > if(!n) { \
    >
    > cout << #n << " failed on line " << __LINE__ << endl; \
    >
    > } \
    >
    > else { \
    >
    > cout << #n << " passed on line " << __LINE__ << endl; \
    >
    > }
    >
    > #endif
    >
    > int main() {
    >
    > bool flag = true;
    >
    > int num = 5;
    >
    > ASSERT(flag == true);
    >
    > ASSERT(flag == false);
    >
    > // when I change the below to ASSERT((num == 5)); it works perfectly.
    >
    > // what's wrong with the version below?
    >
    > ASSERT(num == 5);[/color]

    Think about it. What does the line above expand to?[color=blue]
    >
    > return 0;
    >
    > }
    >[/color]

    HTH,
    --ag

    --
    Artie Gold -- Austin, Texas

    "What they accuse you of -- is what they have planned."

    Comment

    • Alf P. Steinbach

      #3
      Re: Custom ASSERT macro

      * Stephen Tyndall:[color=blue]
      > I know the preprocessor is evil, but I'd like to know what's going on in the
      > following code.
      >
      > The problem is when the num variable is used in the ASSERT macro inside
      > main(). When running the code, I get the following error from Visual
      > C++.NET 2003:
      >
      > warning C4806: '==' : unsafe operation: no value of type 'bool' promoted to
      > type 'int' can equal the given constant
      >
      > #define DEBUG 2
      >
      > #include <iostream>
      >
      > using namespace std;
      >
      > #if DEBUG == 0
      >
      > #define ASSERT(n)
      >
      > #elif DEBUG == 1
      >
      > #define ASSERT(n) if(!n) { cout << #n << " failed" << endl; }
      >
      > #elif DEBUG == 2
      >
      > #define ASSERT(n) \
      >
      > if(!n) { \
      >
      > cout << #n << " failed on line " << __LINE__ << endl; \
      >
      > } \
      >
      > else { \
      >
      > cout << #n << " passed on line " << __LINE__ << endl; \
      >
      > }
      >
      > #endif
      >
      > int main() {
      >
      > bool flag = true;
      >
      > int num = 5;
      >
      > ASSERT(flag == true);
      >
      > ASSERT(flag == false);
      >
      > // when I change the below to ASSERT((num == 5)); it works perfectly.
      >
      > // what's wrong with the version below?
      >
      > ASSERT(num == 5);
      >
      > return 0;
      >
      > }[/color]

      Check out operator precedence. How is the following parsed?

      cout << flag == true << " failed." << endl;

      I'm surprised it even compiles, but it's late and I don't want
      to think about why it could compile right now...

      Hth.

      --
      A: Because it messes up the order in which people normally read text.
      Q: Why is it such a bad thing?
      A: Top-posting.
      Q: What is the most annoying thing on usenet and in e-mail?

      Comment

      • Alf P. Steinbach

        #4
        Re: Custom ASSERT macro

        * Alf P. Steinbach:[color=blue]
        > * Stephen Tyndall:[color=green]
        > > I know the preprocessor is evil, but I'd like to know what's going on in the
        > > following code.
        > >
        > > The problem is when the num variable is used in the ASSERT macro inside
        > > main(). When running the code, I get the following error from Visual
        > > C++.NET 2003:
        > >
        > > warning C4806: '==' : unsafe operation: no value of type 'bool' promoted to
        > > type 'int' can equal the given constant
        > >
        > > #define DEBUG 2
        > >
        > > #include <iostream>
        > >
        > > using namespace std;
        > >
        > > #if DEBUG == 0
        > >
        > > #define ASSERT(n)
        > >
        > > #elif DEBUG == 1
        > >
        > > #define ASSERT(n) if(!n) { cout << #n << " failed" << endl; }
        > >
        > > #elif DEBUG == 2
        > >
        > > #define ASSERT(n) \
        > >
        > > if(!n) { \
        > >
        > > cout << #n << " failed on line " << __LINE__ << endl; \
        > >
        > > } \
        > >
        > > else { \
        > >
        > > cout << #n << " passed on line " << __LINE__ << endl; \
        > >
        > > }
        > >
        > > #endif
        > >
        > > int main() {
        > >
        > > bool flag = true;
        > >
        > > int num = 5;
        > >
        > > ASSERT(flag == true);
        > >
        > > ASSERT(flag == false);
        > >
        > > // when I change the below to ASSERT((num == 5)); it works perfectly.
        > >
        > > // what's wrong with the version below?
        > >
        > > ASSERT(num == 5);
        > >
        > > return 0;
        > >
        > > }[/color]
        >
        > Check out operator precedence. How is the following parsed?
        >
        > cout << flag == true << " failed." << endl;
        >
        > I'm surprised it even compiles, but it's late and I don't want
        > to think about why it could compile right now...[/color]

        Yes it's late, it's late late late, and me Very Sleepy (TM).

        Of course it's not expanded like that; you have # in there.

        It's the 'if' condition expansion of the last assert that's
        the problem, as Artie Gold pointed out.

        --
        A: Because it messes up the order in which people normally read text.
        Q: Why is it such a bad thing?
        A: Top-posting.
        Q: What is the most annoying thing on usenet and in e-mail?

        Comment

        • Stephen Tyndall

          #5
          Re: Custom ASSERT macro

          "Artie Gold" <artiegold@aust in.rr.com> wrote in message
          news:2lopqmFfb7 h8U1@uni-berlin.de...[color=blue]
          > Stephen Tyndall wrote:[color=green]
          > > I know the preprocessor is evil, but I'd like to know what's going on in[/color][/color]
          the[color=blue][color=green]
          > > following code.
          > >
          > > The problem is when the num variable is used in the ASSERT macro inside
          > > main(). When running the code, I get the following error from Visual
          > > C++.NET 2003:
          > >
          > > warning C4806: '==' : unsafe operation: no value of type 'bool' promoted[/color][/color]
          to[color=blue][color=green]
          > > type 'int' can equal the given constant
          > >
          > > #define DEBUG 2
          > >
          > > #include <iostream>
          > >
          > > using namespace std;
          > >
          > > #if DEBUG == 0
          > >
          > > #define ASSERT(n)
          > >
          > > #elif DEBUG == 1
          > >
          > > #define ASSERT(n) if(!n) { cout << #n << " failed" << endl; }
          > >
          > > #elif DEBUG == 2
          > >
          > > #define ASSERT(n) \
          > >
          > > if(!n) { \
          > >
          > > cout << #n << " failed on line " << __LINE__ << endl; \
          > >
          > > } \
          > >
          > > else { \
          > >
          > > cout << #n << " passed on line " << __LINE__ << endl; \
          > >
          > > }
          > >
          > > #endif
          > >
          > > int main() {
          > >
          > > bool flag = true;
          > >
          > > int num = 5;
          > >
          > > ASSERT(flag == true);
          > >
          > > ASSERT(flag == false);
          > >
          > > // when I change the below to ASSERT((num == 5)); it works perfectly.
          > >
          > > // what's wrong with the version below?
          > >
          > > ASSERT(num == 5);[/color]
          >
          > Think about it. What does the line above expand to?[/color]

          Oh. I should have realized that, especially with the parentheses thing;
          sorry, I'm new at this. Thanks for the help, and the quick response.
          [color=blue][color=green]
          > >
          > > return 0;
          > >
          > > }[/color][/color]


          Comment

          • Ivan Vecerina

            #6
            Re: Custom ASSERT macro

            "Stephen Tyndall" <swtyndall@hotm ail.com> wrote in message
            news:Os6dnSD83Y yFrWrdRVn-ug@comcast.com. ..[color=blue]
            > #define ASSERT(n) if(!n) { cout << #n << " failed" << endl; }[/color]

            Besides the missing parentheses, this definition of ASSERT has another
            serious problems.
            When defining statement macros, you should always think of constructs such
            as:
            Consider:
            if( b )
            ASSERT( a );
            else
            { /* do stuff */ }
            Here the extra ';' after the { } of the expanded macro will prevent 'else'
            from being interpreted correctly.
            A common solution to this issue is to enclose the contents of the macro in a
            do...while(fals e) block:
            #define ASSERT(n) do{ if(!n) { cout << #n << " failed" << endl; } }
            while(false)

            hth
            Ivan
            --
            http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form
            Brainbench MVP for C++ <> http://www.brainbench.com


            Comment

            • Ivan Vecerina

              #7
              Re: Custom ASSERT macro

              > #define ASSERT(n) do{ if(!n) { cout << #n << " failed" << endl; } }
              Of course this should be (without the copy-pasted error):
              #define ASSERT(n) do{ if(!(n)) { cout << #n << " failed" << endl; } }


              Actually, to avoid requiring client code to include <iostream>
              (and maybe also to reduce code bloat and possibly improve performance),
              I usually prefer to implement ASSERT as something like:

              extern void assert_notify_f ailure(const char* str); // may also take
              __FILE__ & __LINE__
              #define ASSERT(n) if(n){}else assert_notify_f ailure(#n)
              //here the if+else trick is an alternative to do..while(false )

              //then in some implementation file:
              #include <iostream>
              void assert_notify_f ailure(const char* str)
              {
              std::cerr << str << " failed" << std::endl;
              }


              That's it this time ;)
              Ivan
              --
              http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form


              Comment

              • Stephen Tyndall

                #8
                Re: Custom ASSERT macro

                "Ivan Vecerina" <NOT_VALID_plea se_use_contact_ webform@vecerin a.com> wrote in
                message news:cd82vj$4d5 $1@newshispeed. ch...[color=blue][color=green]
                > > #define ASSERT(n) do{ if(!n) { cout << #n << " failed" << endl; } }[/color]
                > Of course this should be (without the copy-pasted error):
                > #define ASSERT(n) do{ if(!(n)) { cout << #n << " failed" << endl; } }
                >
                >
                > Actually, to avoid requiring client code to include <iostream>
                > (and maybe also to reduce code bloat and possibly improve performance),
                > I usually prefer to implement ASSERT as something like:
                >
                > extern void assert_notify_f ailure(const char* str); // may also take
                > __FILE__ & __LINE__
                > #define ASSERT(n) if(n){}else assert_notify_f ailure(#n)
                > //here the if+else trick is an alternative to do..while(false )
                >
                > //then in some implementation file:
                > #include <iostream>
                > void assert_notify_f ailure(const char* str)
                > {
                > std::cerr << str << " failed" << std::endl;
                > }[/color]

                I was pretty sure the macro I posted wasn't that good; it's from a book I'm
                learning from. I don't know a lot about that kind of thing yet but it felt
                kind of sloppy somehow.

                Thanks for the reply. I'll cut and paste your version of ASSERT for later
                use.


                Comment

                Working...