[...]
Since an unsuccessful assert() terminates the program (unless
you're doing tricky things with SIGABRT), an assert() that fires
with "high probability" means the program dies with that same
high probability -- which indicates that the program is not very
useful, because it keeps dying!
Then you thought that the assert can be used to debug the program,
not for error handling.
Yes, more or less. The actual effect of an assert() is
to cause a programming error to behave predictably and quite
visibly, which is useful as a starting point for debugging.
In the debug side, we used assert to check if all tests passed or
not,
if passed, then we can disable the assert statements in nodebug mode
for
it cost any time.
There are two (or more) schools of thought on this topic.
One approach sprinkles assert() liberally throughout the code
during development and then disables them all for "release"
versions or when performance measurements become important.
Another says "ship what you tested" and leaves the assert()
calls enabled even in the final product, the idea being that
the end user may do things the test suite didn't anticipate.
In large projects a blended strategy may be used: Load the
code with tons and tons of assert() calls during development,
tagging each with an "importance" or "level." In the release
version, disable the less important calls but leave the critical
assertions intact. Sometimes a wrapper along the lines of
extern enum { RELEASE, NORMAL, PARANOID } debugLevel;
#define ASSERT(level,truth) \
assert(debugLevel < (level) || (truth))
...
session = idToSession(sessionID);
ASSERT(RELEASE, session != NULL);
...
ASSERT(PARANOID, expensiveSanityCheck());
...
.... can be used for the "tagging."
I am clear now, I think. We should design another
way to handle error code, such as by return status. Am I right?
It depends on what you mean by "error." Usually, there
are many possible kinds of error, including (but not limited to)
- Logic errors: The programmer reasoned incorrectly or from
incorrect precepts, so the code does not behave as desired
- Implementation errors: The programmer chose the right
algorithm, but slipped up in coding it
- Environmental errors: The code is fine, but for some reason
the "configfile.dat" file can't be opened
- User errors: While running the program, the user entered
his date of birth as 1964-02-30
An assert() can be helpful in cases like the first two, but is
probably not appropriate for the final two.
Ah, yes, we should add -D before NDEBUG, thanks.
You might also want to review just how many .c files are
being compiled, and where the -o sends the output ...