Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where should assert() be used in C resp. C++?

Tags:

What are the places we should use the assert() function specifically? If it's a situation like determining if an integer value is greater than zero or a pointer is null, we can simply use a private function to check this. In this kind of situation, where should we use assert() over a custom written check?

like image 296
Izza Avatar asked Feb 02 '12 06:02

Izza


People also ask

How is assert used in C?

The C library macro void assert(int expression) allows diagnostic information to be written to the standard error file. In other words, it can be used to add diagnostics in your C program.

Where is assert defined in C?

The assert. h header file of the C Standard Library provides a macro called assert which can be used to verify assumptions made by the program and print a diagnostic message if this assumption is false.

Should I use assert in C?

You should only use assert to check for situations that "can't happen", e.g. that violate the invariants or postconditions of an algorithm, but probably not for input validation (certainly not in libraries). When detecting invalid input from clients, be friendly and return an error code.

When should assert be used?

Assertions should be used to check something that should never happen, while an exception should be used to check something that might happen. For example, a function might divide by 0, so an exception should be used, but an assertion could be used to check that the harddrive suddenly disappears.


1 Answers

Context: I write server software for a living, the kind that stays up for weeks before the next version is loaded. So my answers may be biaised toward highly defensive code.

The principle.

Before we delve into the specifics of where to use assert, it's important to understand the principle behind it.

assert is an essential tool in Defensive Programming. It helps validating assumptions (assert them actually) and thus catch programming errors (to be distinguished from user errors). The goal of assert is to detect erroneous situations, from which recovery is generally not immediately possible.

Example:

char const* strstr(char const* haystack, char const* needle) {   assert(haystack); assert(needle);    // ... } 

Alternatives.

In C ? There is little alternative. Unless your function has been designed to be able to pass an error code or return a sentinel value, and this is duly documented.

In C++, exceptions are a perfectly acceptable alternative. However, an assert can help produce a memory dump so that you can see exactly what state the program is in at the moment the erroneous situation is detected (which helps debugging), while an exception will unwind the stack and thus lose the context (oups...).

Also, an exception might (unfortunately) get caught by a high level handler (or an unsavory catch from a fellow developer (you would not do that, of course)), in which case you could miss completely the error until it's too late.

Where NOT to use it.

First, it should be understood that assert is only ever useful in Debug code. In Release, NDEBUG is defined and no code is generated. As a corollary, in Release assert has the same worth as a comment.

  • Never use it for checks that are necessary to the good behavior of the software. Error conditions should be checked and dealt with. Always.

Second, it should be understood that malformed input is part of your life. Would you want your compiler display an assert message each time you make an error ? Hum! Therefore:

  • Never use it for input data validation. Input data should be validated and errors appropriately reported to the user. Always.

Third, it should be understood that crashes are not appreciated. It is expected of your program that it will run smoothly. Therefore, one should not get tempted to leave asserts on in Release mode: Release code ends up in the end user hands and should never crash, ever. At worst, it should shutdown while displaying an error message. It is expected that no user data is lost during this process, and even better if upon restarting the user is taken back to where she was: that is what modern browsers do, for example.

  • Never leave asserts on in Release.

Note: for server code, upon "hitting" an assertion, we manage to get back in position for treating the next query in most cases.

Where to use it.

assert is on in Debug mode, and so should be used for Debugging. Whenever you test new code, whenever your test suite run, whenever software is in your (or your teammates) hands, whenever software is in you QA department hands. Asserts let you spot errors and gives you the full context of the error so that you can repair.

  • Use it during the development and testing cycles.

Even better. Since you know code will not be executed in Release you can afford to perform expensive checks.

Note: you should also test the Release binary, if only to check the performance.

And in Release ?

Well, in the codebase I work on, we replace the inexpensive asserts (the others are ignored) by specific exceptions that are only caught by a high level handler that will log the issue (with backtrace), return a pre-encoded error response and resume the service. The development team is notified automatically.

In software that is deployed, the best practices I have seen imply to create a memory dump and stream it back to the developers for analysis while attempting not to lose any user data and behave as courteously as possible toward the unfortunate user. I feel really blessed to be working server-side when I contemplate the difficulty of this task ;)

like image 147
Matthieu M. Avatar answered Oct 15 '22 08:10

Matthieu M.