NDEBUG and assert macros.

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

    NDEBUG and assert macros.

    Ok, so once I'm done debugging my code(split across multiple modules)
    using the assert macro, I would want to switch off all the assert
    macros ued in the program. Does this mean I have to include:

    #define NDEBUG

    in every .c where I used assert or defining it one file would turn off
    all assert macros in every file ?
  • Nick Keighley

    #2
    Re: NDEBUG and assert macros.

    On 1 Aug, 10:44, pereges <Brol...@gmail. comwrote:
    Ok, so once I'm done debugging my code(split across multiple modules)
    using the assert macro, I would want to switch off all the assert
    macros ued in the program. Does this mean I have to include:
    >
    #define NDEBUG
    >
    in every .c where I used assert or defining it one file would turn off
    all assert macros in every file ?
    It's going to have to be in every compilation unit (c file +
    includes).
    Many compilers support a -D option which enables you to define a macro
    on the compilers command line.

    gcc -DNDEBUG fred.c -ofred

    or you could it in a header file and include the header file
    in every c file. Then at least next time you'd only need
    to change one file.

    Some pitfalls with turning off assert()s. Are you *certain*
    that none of them are essential eg. input validation.
    Are you sure none of them have side effects?

    assert (fopen (s, siseof s, in) != NULL);

    --
    Nick Keighley

    ... it is absurd to make elaborate security checks on
    debugging runs, when no trust is put in the results, and
    then remove them in production runs, when an erroneous
    result could be expensive or disastrous.
    C. A. R. Hoare

    Comment

    • Jens Thoms Toerring

      #3
      Re: NDEBUG and assert macros.

      pereges <Broli00@gmail. comwrote:
      Ok, so once I'm done debugging my code(split across multiple modules)
      using the assert macro, I would want to switch off all the assert
      macros ued in the program. Does this mean I have to include:
      #define NDEBUG
      in every .c where I used assert or defining it one file would turn off
      all assert macros in every file ?
      Every .c file that uses assert() must see the define. You can achieve
      that by putting the line in every file. On the other hand, in a pro-
      ject with a lot of source files one tends to have a header file that
      gets included everywhere. If you have such a header file than the
      simplest thing would be to put the define in that file.

      Regards, Jens
      --
      \ Jens Thoms Toerring ___ jt@toerring.de
      \______________ ____________ http://toerring.de

      Comment

      • rahul

        #4
        Re: NDEBUG and assert macros.

        On Aug 1, 2:44 pm, pereges <Brol...@gmail. comwrote:
        Ok, so once I'm done debugging my code(split across multiple modules)
        using the assert macro, I would want to switch off all the assert
        macros ued in the program. Does this mean I have to include:
        >
        #define NDEBUG
        >
        in every .c where I used assert or defining it one file would turn off
        all assert macros in every file ?
        <off-topic>
        If you compiler supports defining it on invocation, you can have that
        on the command line itself(gcc supports doing that). The general
        approach is to have a Makefile with targets defined for both the
        cases(defined and not defined). Even if you are debugging a single
        file, a simple Makefile won't hurt. That will save you the trouble of
        typing the macro definition again on again while compiling it.
        </off-topic>

        The other approach, would be to have the macro defined in a header
        file and include it in every file you use. Before defining NDEBUG,
        make sure that your assert() is not having any side effects.

        assert ((fp = fopen (FILE_NAME, "rb")) != NULL); /*this will break
        you code

        /* the proper way to do it
        fp = fopen (FILE_NAME, "rb");
        assert (fp != NULL);
        >assert (fopen (s, siseof s, in) != NULL);
        I assume Nick either meant fgets or passed incorrect arguments to
        fopen.

        Comment

        • blargg

          #5
          Re: NDEBUG and assert macros.

          In article
          <26daab2c-b649-4112-be02-5a2c448d1b0a@v8 g2000prm.google groups.com>, rahul
          <rahulsinner@gm ail.comwrote:
          ...
          assert ((fp = fopen (FILE_NAME, "rb")) != NULL); /*this will break
          you code */
          >
          /* the proper way to do it */
          fp = fopen (FILE_NAME, "rb");
          assert (fp != NULL);
          BAD example, since failure to open a file is ALWAYS a possibility, no
          matter how well-debugged a program is. Assert is NOT for input validation,
          only validation of data from other parts of the program.

          Comment

          • William Pursell

            #6
            Re: NDEBUG and assert macros.

            On 1 Aug, 10:44, pereges <Brol...@gmail. comwrote:
            Ok, so once I'm done debugging my code(split across multiple modules)
            using the assert macro, I would want to switch off all the assert
            macros ued in the program. Does this mean I have to include:
            >
            #define NDEBUG
            >
            in every .c where I used assert or defining it one file would turn off
            all assert macros in every file ?
            Actually, you need to ensure that NDEBUG is defined at the
            point assert.h is included. So, if you write:

            #include <assert.h>
            #define NDEBUG

            then assertions will still be enabled. It is generally (IMO)
            a bad idea to define NDEBUG in the source itself. Instead,
            define NDEBUG when you invoke your compiler. For example,
            any of the following work in many environments:

            $ $CC -DNDEBUG ... # Here, $CC is the path to your compiler
            $ make CPPFLAGS=-DNDEBUG
            $ ./configure CPPFLAGS=-DNDEBUG && make

            Comment

            • William Pursell

              #7
              Re: NDEBUG and assert macros.

              On 1 Aug, 10:57, Nick Keighley <nick_keighley_ nos...@hotmail. com>
              wrote:
              >On 1 Aug, 10:44, pereges <Brol...@gmail. comwrote:
              >Ok, so once I'm done debugging my code(split across multiple modules)
              >using the assert macro, I would want to switch off all the assert
              >macros ued in the program.
              <snip>
              Some pitfalls with turning off assert()s. Are you *certain*
              that none of them are essential eg. input validation.
              Are you sure none of them have side effects?
              If a program is using assert to validate input,
              then it is abusing/misusing assert. If an assertion
              has a side effect, it is a bug, for example:
              assert( x = 0 ); /* oops, should be x == 0 */

              In other words, if you can't turn off assertions and
              still pass the test suite, the solution is to fix
              the bug--it is *not* to avoid turning off the assertions.
              The point relevant to the OP is that you are NOT
              done debugging until you've turned off the assertions
              and verified that the code still works.


              Comment

              • William Pursell

                #8
                Re: NDEBUG and assert macros.

                On 1 Aug, 12:31, rahul <rahulsin...@gm ail.comwrote:

                /* the proper way to do it
                fp = fopen (FILE_NAME, "rb");
                assert (fp != NULL);
                No. Absolutely NOT. This is utterly broken, wrong, and
                heinous. This is NOT what assert is for. At all. Arghh.
                If you want, you might do:

                fp = Fopen( ... );
                assert( fp != NULL );

                This would serve as documentation to the maintainer that
                the Fopen call will never return a NULL pointer. Or you
                can do things like:

                for( i = 0; i < N; i++) {
                ...
                }
                assert( i == N);

                This documents to the maintainer that the loop
                is constructed such that it will always terminate with i
                hitting the upper bound. The purpose of assert is to
                validate that something you believe must be true is
                in fact true. Often as pre-conditions in a function call:

                void add( const int *a, const int *b, int *c, size_t N )
                {
                size_t i;
                assert( a != NULL );
                assert( b != NULL );
                assert( c != NULL );

                for( i = 0; i < N; i++ )
                c[i] = a[i] + b[i];
                }

                This is far safer than simply adding a comment that states
                that none of the arguments can be a null pointer, since it
                aborts when the unwary programmer attempts to pass a null
                pointer. It is NOT doing validation. If you want to write
                a function that validates, you can't use assert. For example:

                int add( int *a, int *b, int *c)
                {
                int status = 0;
                int A,B;

                A = ( a == NULL ) ? 0 : *a;
                B = ( b == NULL ) ? 0 : *b;
                if( c == NULL )
                status = -1
                else
                *c = A + B;
                return status;
                }

                Here, there are some questions. For example, perhaps you want
                this function to never overflow. So perhaps you might want to
                ensure that it is never called with *a or *b larger than INT_MAX/2.
                In that case, look through your code; if you believe that
                condition is true, then make it an assertion.

                assert is NOT for data validation, or to check a function call.
                It is used to validate your logic and the implementation. It
                should be thought of as documentation. You are telling both
                the compiler and the maintainer that you believe something
                will be true. If it is not, the compiler will tell you that
                you are wrong by causing a run-time abort. Anytime you look at
                a piece of code and think something like, "okay, right here,
                either i is positive or j is odd", then write it out:
                assert( i 0 || j % 2 );
                This is much better than a comment for two reasons ( at least ):
                1) It removes the ambiguity about the word "positive" (does it
                include zero or not?)
                2) It is validated by the compiler.


                Comment

                • vippstar@gmail.com

                  #9
                  Re: NDEBUG and assert macros.

                  On Aug 2, 12:54 pm, William Pursell <bill.purs...@g mail.comwrote:
                  On 1 Aug, 12:31, rahul <rahulsin...@gm ail.comwrote:
                  >
                  /* the proper way to do it
                  fp = fopen (FILE_NAME, "rb");
                  assert (fp != NULL);
                  >
                  No. Absolutely NOT. This is utterly broken, wrong, and
                  heinous. This is NOT what assert is for. At all. Arghh.
                  It might not be what assert is for, but it's not broken or wrong. (if
                  you don't mind the missing */)

                  <snip>

                  Comment

                  • santosh

                    #10
                    Re: NDEBUG and assert macros.

                    William Pursell wrote:
                    On 1 Aug, 12:31, rahul <rahulsin...@gm ail.comwrote:
                    >
                    >
                    >/* the proper way to do it
                    >fp = fopen (FILE_NAME, "rb");
                    >assert (fp != NULL);
                    >
                    No. Absolutely NOT. This is utterly broken, wrong, and
                    heinous. This is NOT what assert is for. At all. Arghh.
                    If you want, you might do:
                    >
                    fp = Fopen( ... );
                    assert( fp != NULL );
                    >
                    This would serve as documentation to the maintainer that
                    the Fopen call will never return a NULL pointer. Or you
                    can do things like:
                    >
                    for( i = 0; i < N; i++) {
                    ...
                    }
                    assert( i == N);
                    >
                    This documents to the maintainer that the loop
                    is constructed such that it will always terminate with i
                    hitting the upper bound. The purpose of assert is to
                    validate that something you believe must be true is
                    in fact true. Often as pre-conditions in a function call:
                    >
                    void add( const int *a, const int *b, int *c, size_t N )
                    {
                    size_t i;
                    assert( a != NULL );
                    assert( b != NULL );
                    assert( c != NULL );
                    >
                    for( i = 0; i < N; i++ )
                    c[i] = a[i] + b[i];
                    }
                    >
                    This is far safer than simply adding a comment that states
                    that none of the arguments can be a null pointer, since it
                    aborts when the unwary programmer attempts to pass a null
                    pointer. It is NOT doing validation. If you want to write
                    a function that validates, you can't use assert. For example:
                    >
                    int add( int *a, int *b, int *c)
                    {
                    int status = 0;
                    int A,B;
                    >
                    A = ( a == NULL ) ? 0 : *a;
                    B = ( b == NULL ) ? 0 : *b;
                    if( c == NULL )
                    But is it any more correct call this add with null pointer values
                    for 'a', 'b', or 'c' than a similar call of the previous add? Why would
                    one want to write a zero to *c when the function is called with clearly
                    invalid arguments. I personally would return the error value for all
                    these cases, not just when c is NULL.

                    I can't really decide whether using assert on function parameters is
                    appropriate or not. An error code, as in this code, might be silently
                    misused by the caller, but OTOH, it somehow seems better to *inform*
                    the caller of an erroneous call (thus giving it a chance to retry,
                    though how much real life code is this comprehensive?) , than terminate
                    the program single-handedly. But then would checking parameters with
                    assert be more justified for a function that has no defined error
                    return codes?

                    IMHO assert seems much more appropriate when used to verify the
                    correctness of program state at various points than when it's used for
                    things like function parameter checking, return value checking etc.
                    status = -1
                    else
                    *c = A + B;
                    return status;
                    }
                    >
                    Here, there are some questions. For example, perhaps you want
                    this function to never overflow. So perhaps you might want to
                    ensure that it is never called with *a or *b larger than INT_MAX/2.
                    In that case, look through your code; if you believe that
                    condition is true, then make it an assertion.
                    In the calling code? If so I agree.

                    <snip>

                    Comment

                    Working...