Use of assert.h

M

Michael Wojcik

assert should be used to find bugs in your program.

My point is precisely that no, it shouldn't, because it's a terrible
error-handling mechanism. It provides no recovery and poor reporting.
Example:
for (i = 0; i < n; ++i) a = 0;
assert (i >= n && (n < 0 || i == n));

After execution of the loop, i will be equal to n, except if n was
negative. There will be no assertion unless I made some mistake in this
tiny bit of code. If I made a mistake, then how could I possibly handle
it?


By logging the problem, using the program's logging mechanism (which
could be trivial, if it's a trivial program, or complex if it isn't),
and returning an error to the caller.
Incorrect inputs are not bugs in the program and therefore should never
be handled by an assert.

True, but too narrow. Nothing should ever be "handled" by assert,
because it's an astoundingly poor way of "handling" things.

And please note that in this thread Chuck and I were both discussing
incorrect input to low-level functions, which could very well be bugs
in the program (such as passing a null pointer to a function which
requires a non-null one).
 
P

pete

Rob said:
In general, is it considered bad practice to use asserts in production
code?

I only use assert to make sure that any macros
which are intended to be readily changeable by the programmer,
retain valid values.
 
J

John Smith

Richard said:
Correct, but still not useful. I find it very hard to debug when all
information I have is "My program just crashed. It said 'assertion
something', and then some numbers. No, I didn't write down the numbers."

Richard

The numbers aren't meaningless. Presumably you put the assert statement
there in the first place because you thought you might have a bug at
line number xxxx. The assert message will tell you that yes, by golly,
something IS happening at line xxxx that isn't kosher. Personally, I
would find that useful for debugging and I would distinguish it from
code that is intended, for example, to check whether input can be
processed appropriately and "handle" it if it can't be.

-JS
 
C

Chris Croughton

The numbers aren't meaningless. Presumably you put the assert statement
there in the first place because you thought you might have a bug at
line number xxxx. The assert message will tell you that yes, by golly,
something IS happening at line xxxx that isn't kosher. Personally, I
would find that useful for debugging and I would distinguish it from
code that is intended, for example, to check whether input can be
processed appropriately and "handle" it if it can't be.

But how do you know what the actual value was that caused the assert to
fail? That information can be very useful in tracking the bug, whereas
"something's wrong at line 3456" doesn't tell you anything at all about
the data.

assert(x <= 10);

traps the error, but doesn't tell you whether x is 11 or 2147483647.

It's also difficult with a source debugger to insert a breakpoint where
the error has occurred, whereas:

#ifndef NDEBUG
if (x > 10)
{
do_log(LOG_ERROR, "x (%d) > 10\n", x);
abort();
}
#endif

not only logs the information but also provides a handy place to put a
breakpoint so that you can trace the stack or whatever.

Chris C
 
J

John Smith

Chris said:
But how do you know what the actual value was that caused the assert to
fail? That information can be very useful in tracking the bug, whereas
"something's wrong at line 3456" doesn't tell you anything at all about
the data.

Before you can start looking at erroneous values you have to know where
they occur.
assert(x <= 10);

traps the error, but doesn't tell you whether x is 11 or 2147483647.

printf("x: %d\n", x); /* I know some people hate this kind of thing */
It's also difficult with a source debugger to insert a breakpoint where
the error has occurred, whereas:

#ifndef NDEBUG
if (x > 10)
{
do_log(LOG_ERROR, "x (%d) > 10\n", x);
abort();
}
#endif

This is perfectly fine, if you don't mind writing seven lines of code
instead of one (not including, of course, the implementation of do_log).
 
J

Jan Danielsson

Chris Croughton wrote:
[---]
But how do you know what the actual value was that caused the assert to
fail? That information can be very useful in tracking the bug, whereas
"something's wrong at line 3456" doesn't tell you anything at all about
the data.

assert(x <= 10);

traps the error, but doesn't tell you whether x is 11 or 2147483647.

Obviously, knowing the value isn't relevant when you use assert(),
because if it was, then you're probably not going to use assert().
Asserts are meant to abort the application and tell you where it
aborted. No more, no less. If you want it to output something more, then
don't use assert().

When an assert() has aborted the program, that means that there's no
point in continuing execution - because something had gone very wrong.
Because it is an assert(), it's obvious from the context what went wrong
(or rather, it's obvious where the application needs to be debugged). If
it's not, you're using asserts wrong (IMHO).
It's also difficult with a source debugger to insert a breakpoint where
the error has occurred, whereas:

#ifndef NDEBUG
if (x > 10)
{
do_log(LOG_ERROR, "x (%d) > 10\n", x);
abort();
}
#endif

not only logs the information but also provides a handy place to put a
breakpoint so that you can trace the stack or whatever.

That would assume that the value of x is interresting. It's not
always. When it is, you output it before terminating. If it's not
interresting, then why not just use assert()?

It seems that some of those advocating against assert() think that
you either use one or the other method, and that's impossible to mix
them. In my fatal error management code, I have in the area of 5%
assert() calls, and the rest calls which look much like your snippet
above. Sometimes, it's just a waste of time and space to use anything
more than assert().
 
R

Richard Bos

John Smith said:
The numbers aren't meaningless.

Not to the programmer. To the average user, though, an assert() warning
might as well have been in Proto-Elamite; and good luck trying to get
dependable line numbers out of them.

Richard
 
S

SM Ryan

# Not to the programmer. To the average user, though, an assert() warning
# might as well have been in Proto-Elamite; and good luck trying to get
# dependable line numbers out of them.

It's far better to run production code with no checking to give user the false
impression that all is well, rather than giving them some hint there is a
problem and they need help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,430
Latest member
7dog123

Latest Threads

Top