Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > How does assert benefit your code really?

Reply
Thread Tools

How does assert benefit your code really?

 
 
lovecreatesbeauty
Guest
Posts: n/a
 
      04-11-2006
Besides printing out for example

" a.out: p113.c:8: main: Assertion `0' failed.
Aborted "

and a switch option NDEBUG, what other benefits does assert() provide
in any scope of designing, debugging/coding and/or testing?

Do you prefer the if statement of the language to the assert MACRO of
the precompiler?

--
lovecreatesbeauty

 
Reply With Quote
 
 
 
 
Kiru Sengal
Guest
Posts: n/a
 
      04-11-2006

lovecreatesbeauty wrote:
> Besides printing out for example
>
> " a.out: p113.c:8: main: Assertion `0' failed.
> Aborted "
>
> and a switch option NDEBUG, what other benefits does assert() provide
> in any scope of designing, debugging/coding and/or testing?
>
> Do you prefer the if statement of the language to the assert MACRO of
> the precompiler?
>


assert is usually used to catch logical errors in your program, that if
deemed nonexistant after proper testing (noticing that the assert never
fires), would not require the error checking anymore in your finished
product

 
Reply With Quote
 
 
 
 
Pedro Graca
Guest
Posts: n/a
 
      04-11-2006
lovecreatesbeauty wrote:
> Besides printing out for example
>
> " a.out: p113.c:8: main: Assertion `0' failed.
> Aborted "
>
> and a switch option NDEBUG, what other benefits does assert() provide
> in any scope of designing, debugging/coding and/or testing?
>
> Do you prefer the if statement of the language to the assert MACRO of
> the precompiler?


[newbie answering]
To me, assert() and if() are two completely different things, each used
for completely different reasons.

#include <assert.h>
int main(void) {
assert(argc >= 2); /* wrong use of assert() */
if (CHAR_BIT > { /* wrong use of if() */
exit(EXIT_FAILURE);
}
return 0;
}


Or, for a more likely example, let's say you have a function that sums
all the int's in an array of some size. In the function description you
say the array must not be empty.

int sum_array(const int * array, size_t elems) {
int x = 0;
assert(array != NULL);
while (elems--) x += *array++;
return x;
}

When this code is compiled with NDEBUG defined there will be no checks
in place to catch programmer's mistakes.

--
If you're posting through Google read <http://cfaj.freeshell.org/google>
 
Reply With Quote
 
Bill Pursell
Guest
Posts: n/a
 
      04-11-2006
lovecreatesbeauty wrote:
> Besides printing out for example
>
> " a.out: p113.c:8: main: Assertion `0' failed.
> Aborted "
>
> and a switch option NDEBUG, what other benefits does assert() provide
> in any scope of designing, debugging/coding and/or testing?
>
> Do you prefer the if statement of the language to the assert MACRO of
> the precompiler?


Assert can be your best friend. For example, if instead of:
int
foo(int x, int y)
{ /* Return some function of x and y. Remember, x needs
to be between 5 and 10, and y must be between 15 and 150
or this will segfault!! */
....
}

you write:
int
foo(int x, int y)
{
assert(x > 5 && x <=10);
assert (y >=15 && y<150);
....
}

You get 2 major benefits.
1) Removes the ambiguity inherent in the English description
regarding whether the endpoints are inclusive,
2) When some code is changed so that a caller is using
the wrong arguments, you will be instantly aware of it
when you run, instead of getting a random segfault and
having to track down what caused it.

Also, placing assertions makes it clear to the maintainer
what the coder expected. Any time you expect something
to be true, place an assertion. If it fails, you either have
a coding error somewhere, or your expectation is wrong.
Either is good to know.

Assert is better than if for this type of thing, because it goes
away when you compile your non-debug version. You can
accomplish that with precompiler wrappers around your
if statements, but it is aesthetically unappealing in most
cases.

 
Reply With Quote
 
John Devereux
Guest
Posts: n/a
 
      04-11-2006
"lovecreatesbeauty" <(E-Mail Removed)> writes:

> Besides printing out for example
>
> " a.out: p113.c:8: main: Assertion `0' failed.
> Aborted "
>
> and a switch option NDEBUG, what other benefits does assert() provide
> in any scope of designing, debugging/coding and/or testing?
>
> Do you prefer the if statement of the language to the assert MACRO of
> the precompiler?



One thing you must be really careful of is that the assert() call must
not have any side effects. Otherwise, even after all your extensive
testing is done, the final build will be different and may fail. And
because it only fails when the asserts are gone, you won't know where
the problem is!

for example,

....
unsigned char *fred;
assert((fred = malloc(1000)) != 0);
memset(fred,0,1000);
....

would be a disaster since no memory would get allocated in the release
build.

A stupid mistake... but I did it once!

Also in embedded systems or time or memory critical code, the overhead
of the asserts may be too high to even run the program properly. For
example assert() may bring in printf and the rest of the stdio
library.


--

John Devereux
 
Reply With Quote
 
pemo
Guest
Posts: n/a
 
      04-11-2006
John Devereux wrote:
> "lovecreatesbeauty" <(E-Mail Removed)> writes:
>
>> Besides printing out for example
>>
>> " a.out: p113.c:8: main: Assertion `0' failed.
>> Aborted "
>>
>> and a switch option NDEBUG, what other benefits does assert() provide
>> in any scope of designing, debugging/coding and/or testing?
>>
>> Do you prefer the if statement of the language to the assert MACRO of
>> the precompiler?

>
>
> One thing you must be really careful of is that the assert() call must
> not have any side effects. Otherwise, even after all your extensive
> testing is done, the final build will be different and may fail. And
> because it only fails when the asserts are gone, you won't know where
> the problem is!
>
> for example,
>
> ....
> unsigned char *fred;
> assert((fred = malloc(1000)) != 0);
> memset(fred,0,1000);
> ....
>
> would be a disaster since no memory would get allocated in the release
> build.
>
> A stupid mistake... but I did it once!
>
> Also in embedded systems or time or memory critical code, the overhead
> of the asserts may be too high to even run the program properly. For
> example assert() may bring in printf and the rest of the stdio
> library.


A very good point about the 'type' of things that should/should-not be
/asserted/.

For example, should this be /asserted/ ...

char * p = malloc(10);

assert(p != NULL);

malloc() can legitimably return NULL, so, is this worth asserting, or should
one really build in a proper test, and, if the test proves negative, the
more difficult 'recovery'?

char * p = malloc(10);

if(NULL == p)
{
// Now what? It's all too easy to call abort() etc?
}


--
==============
*Not a pedant*
==============


 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      04-11-2006
John Devereux wrote:
>
> Also in embedded systems or time or memory critical code, the overhead
> of the asserts may be too high to even run the program properly. For
> example assert() may bring in printf and the rest of the stdio
> library.
>

That's where it pays to roll one's own assert macro. If the device has
no means to display the message, don't.

--
Ian Collins.
 
Reply With Quote
 
Manuel Tobias Schiller
Guest
Posts: n/a
 
      04-11-2006
On 2006-04-11, Kiru Sengal <(E-Mail Removed)> wrote:
>
> lovecreatesbeauty wrote:
> assert is usually used to catch logical errors in your program, that if
> deemed nonexistant after proper testing (noticing that the assert never
> fires), would not require the error checking anymore in your finished
> product
>


Sometimes, leaving in a few of those assert statements in the finished
product is a good idea as well because it will give a better indication
of where things fail in production builds (because of misuse of the
program, not buggy coding). I've seen this method being useful in the
printer driver I maintain (a driver to use a certain GDI printer under
*nix-like OS), so I thought sharing this "trick" with others (who might
not yet know it) might be a good idea.

Regards

Manuel
 
Reply With Quote
 
John Devereux
Guest
Posts: n/a
 
      04-11-2006
Ian Collins <(E-Mail Removed)> writes:

> John Devereux wrote:
>>
>> Also in embedded systems or time or memory critical code, the overhead
>> of the asserts may be too high to even run the program properly. For
>> example assert() may bring in printf and the rest of the stdio
>> library.
>>

> That's where it pays to roll one's own assert macro. If the device has
> no means to display the message, don't.


That's what I usually do. For some platforms I set it to just halt the
program, then at least you can usually see what happened in a
debugger.

--

John Devereux
 
Reply With Quote
 
Stephen Sprunk
Guest
Posts: n/a
 
      04-11-2006
"Manuel Tobias Schiller" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Sometimes, leaving in a few of those assert statements in the finished
> product is a good idea as well because it will give a better indication
> of where things fail in production builds (because of misuse of the
> program, not buggy coding). I've seen this method being useful in the
> printer driver I maintain (a driver to use a certain GDI printer under
> *nix-like OS), so I thought sharing this "trick" with others (who might
> not yet know it) might be a good idea.


Robust code should have all kinds of error-checking built in so that if the
impossible happens, it can be silently dealt with. Aborting a production
build in customers' hands is rarely the correct answer.

assert() is useful because, whenever you code in those checks to handle the
impossible, you can put an assert() right before them and crash the code in
a development build (where such is somewhat expected). This prevents bad
things from silently "working" as they would in the production build.

For instance, most of the time when I write a function that is documented to
accept only a non-NULL pointer as a parameter, it'll look like this:

void func(void *param) {

assert(param);
if (!param) return;

/* do useful stuff with param */

}

Anyone using my function incorrectly in a debug build will get a nasty error
and crash making it obvious what they did, whereas if it's due to a bug that
never appeared in testing, the production behavior at least has a chance of
being correct.

One might also redefine assert() to print a message to stderr in production
builds instead of having the test preprocessed out. That's the best of both
worlds.

S

--
Stephen Sprunk "Stupid people surround themselves with smart
CCIE #3723 people. Smart people surround themselves with
K5SSS smart people who disagree with them." --Aaron Sorkin

*** Free account sponsored by SecureIX.com ***
*** Encrypt your Internet usage with a free VPN account from http://www.SecureIX.com ***
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
To assert or not to assert... ImpalerCore C Programming 79 05-17-2010 12:47 PM
assert 0, "foo" vs. assert(0, "foo") Thomas Guettler Python 3 02-23-2005 07:53 PM
assert(x) and '#define ASSERT(x) assert(x)' Alex Vinokur C Programming 5 11-25-2004 08:48 PM
RE: remove assert statement (Was: Re: PEP new assert idiom) Robert Brewer Python 1 11-07-2004 06:53 PM



Advertisments