user2799508
user2799508

Reputation: 848

Trying to understand usefulness of assert

What is the usefulness of assert(), when we can also use printf and if-else statements will inform the user that b is 0?

#include <stdio.h>
#include <assert.h>

int main() {
int a, b;

printf("Input two integers to divide\n");
scanf("%d%d", &a, &b);

assert(b != 0);

printf("%d/%d = %.2f\n", a, b, a/(float)b);

return 0;
}

Upvotes: 3

Views: 185

Answers (6)

legends2k
legends2k

Reputation: 33014

There're two things here that people conflate. Validation of run-time errors and compile-time bugs.

Avoid a runtime error with if

Say the user is supposed to enter only numbers, but the input encountered is alphanumeric then it's a run-time error; there's nothing that you, the programmer, can do about it. You've to raise this to the user in a user-friendly, graceful way; this involves bubbling up the error to the right layer, etc. There are multiple ways of doing this: returning error value, throwing an exception, etc. Not all options are available in all languages.

Catch a bug with an assert

On the other hand, there're design-time assumptions and invariants a programmer depends on when writing new code. Say you're authoring a function make_unit_vec involving division of a vector’s components by its length. Passing the 0 vector breaks this function since it’ll lead to a divide-by-zero; an invalid operation. However, you don’t want to check this every time in this function, since you're sure none of the callers will pass the 0 vector -- an assumption, not about extern user input but, about internal systems within programmer’s control.

So the caller of this function should never pass a vector with length 0. What if some other programmer doesn’t know of this assumption and breaks make_unit_vec by passing a 0 vector? To be sure this bug is caught, you put an assert i.e. you're asserting (validating) the design-time assumption you made.

When a debug build is run under the debugger, this assert will "fire" and you can check the call stack to find the erring function! However, beware that assertions don’t fire when running a release build. In our example, in a release build, the div-by-zero will happen, if the erroneous caller isn’t corrected.

This is the rationale behind assert being enabled only for debug builds i.e. when NDEBUG is not set.

Upvotes: 3

Noufal Ibrahim
Noufal Ibrahim

Reputation: 72855

Asserts are not used to inform users about anything. Assertions are used to enforce invariants in your program.

In the above program, the assert is misused. The b != 0 is not an invariant. It is a condition to be checked at runtime and the proper way to do it would be something like

if (b == 0) {
   sprintf(stderr, "Can't divide by 0\n");
   return -1;
}

This means that the program will check user input and then abort if it's incorrect. The assert would be inappropriate because, one, it can be compiled out using the NDEBUG macro which will, in your case, alter program logic (if the input is 0, the program will continue to the printf with the NDEBUG flag) and two because the purpose of an assert is to assert a condition at a point in the program.

The example in the wikipedia article I've linked to gives you a place where an assert is the right thing to use. It helps to ensure program correctness and improves readability when someone is trying to read and understand the algorithm.

Upvotes: 2

Jonathan Leffler
Jonathan Leffler

Reputation: 755114

That is not a good use of assert; validating user input with assert is too brutal for anything other than your own private use.

This is a better example — it is a convenient one I happen to have kicking around:

int Random_Integer(int lo, int hi)
{
    int range = hi - lo + 1;
    assert(range < RAND_MAX);
    int max_r = RAND_MAX - (RAND_MAX % range);
    int r;
    while ((r = rand()) > max_r)
        ;
    return (r % range + lo);
}

If the value of RAND_MAX is smaller than the range of integers requested, this code is not going to work, so the assertion enforces that critical constrain.

Upvotes: 0

Potatoswatter
Potatoswatter

Reputation: 137960

  1. It stops the program and prevents it from doing anything wrong (besides abruptly stopping).

  2. It's like a baked-in breakpoint; the debugger will stop on it without the extra manual work of looking up the line number of the printf and setting a breakpoint. (assert will still helpfully print this information though.)

  3. By default it's defined to be conditional on the NDEBUG macro, which is usually set up to reflect the debug/release build switch in the development environment. This prevents it from decreasing performance or causing bloat for end users.

Note that assert isn't designed to inform the user of anything; it's only for debugging output to the programmer.

Upvotes: 0

Elliott Frisch
Elliott Frisch

Reputation: 201537

assert will stop the program, it marks a condition that should never occur.

From Wikipedia,

When executed, if the expression is false (that is, compares equal to 0), assert() writes information about the call that failed on stderr and then calls abort(). The information it > writes to stderr includes:

the source filename (the predefined macro __FILE__)
the source line number (the predefined macro __LINE__)
the source function (the predefined identifier __func__) (added in C99)
the text of expression that evaluated to 0 [1]

Example output of a program compiled with gcc on Linux:

program: program.c:5: main: Assertion `a != 1' failed.
Abort (core dumped)

Upvotes: 0

Dayal rai
Dayal rai

Reputation: 6606

In your program if the condition b != 0 holds true then the program execution will continue otherwise it is terminated and an error message is displayed and this is not possible with printf only. Using if-else will work too but that is not a MACRO.

Upvotes: 0

Related Questions