tags:

views:

322

answers:

4

I was taking a look at the assert() reference page and I got stuck while I read the given example:

/* assert example */
#include <stdio.h>
#include <assert.h>

int main ()
{
  FILE * datafile;
  datafile=fopen ("file.dat","r");
  assert (datafile);

  fclose (datafile);

  return 0;
}

In this example, assert is used to abort the program execution if datafile compares equal to 0, which happens when the previous call to fopen was not successful.

I totally agree that if fopen() fails, assert() will abort execution. However I'm concerned about the rightness of this example:

In my opinion assert() is there to detect cases that can't normally happen (like passing a NULL pointer to a function whose documentation states it is forbidden).

In this example, failing to open a file is not something that can't normally happen. In fact, I can see dozens of reasons why this would fail. The file couldn't exist, the program could run without required privileges, and so on.

I would rather have done something like:

/* not longer an assert example */
#include <stdio.h>
#include <assert.h>

int main ()
{
  FILE * datafile;
  datafile=fopen ("file.dat","r");

  if (datafile != NULL)
  {
    // Do something, whatever.
    fclose (datafile);
  } else
  {
    // Report the error somehow.
  }

  return 0;
}

Is my understanding of how assert() should be used incorrect ?


EDIT AND GOOD NEWS !

It seems the referred site is ruled by rigorous people. Here is the mail I got back from one of the site maintainer:

Hi Julien, I have to agree, the example code was poorly chosen. It has now been just rewritten to something more appropriate.

Many thanks for pointing this out, and sorry for any inconveniences this may have caused to you.

Best regards,

And the updated example:

/* assert example */
#include <stdio.h>
#include <assert.h>

void print_number(int* myInt) {
  assert (myInt!=NULL);
  printf ("%d\n",*myInt);
}

int main ()
{
  int a=10;
  int * b = NULL;
  int * c = NULL;

  b=&a;

  print_number (b);
  print_number (c);

  return 0;
}

Glad to see that some people do their work well on the Internet ! ;)

+13  A: 

You're perfectly right sir. This is a poor usage of assert.

Alexandre C.
indeed, assert should only be last resort aka world collapse
PoweRoy
Thanks for the feedback. I wrote to the contact page to inform them about the problem. I wonder if they will update it.
ereOn
+1 for this can be potential answer ;-)
Kedar
A: 

Minor notification: it would be better if you write..

FILE * datafile = NULL;

Also, assert only works in debug mode... so your method is better.

shader
Well, this is not my code. And while I usually initialize my local variables, here `datafile` is assigned right after its declaration, so it doesn't really matter ;)Good point about debug mode, I didn't even thought of that.
ereOn
What makes you say it works only in debug mode?
Praveen S
@Praveen: assert is a macro that does something only when `NDEBUG` isn't defined. So usually in debug mode.
ereOn
A: 

This is prefectly fine if this is something that can't happen under normal execution. Eg. if this is the program's own data file. Assert is for catching the developers' mistakes during development. I think it's beyond reasonable to prepare the program for getting its own files damaged or deleted by the user. Also note that you are obfuscating your code with error handling in the second example. Simply putting in such asserts might be the pragmatic thing to do.

Cornelius Scarabeus
If the program for instance doens't have permission to open the file, an error message is better than a failed assert. Don't forget that assert can be skipped by the compiler if `NDEBUG` is `#define`d.
Alexandre C.
Why is proper error handling considered obfuscation if `assert` isn't? Error handling doesn't necessarily mean that you recover gracefully from the error -- just that you detect it and act on it (for example by terminating the process). That can be done just as concisely as an `assert` check.
jalf
@jalf: Well, just look at the example code! Error handling is generally a cross cutting concern, and in the above form, it distracts from the algorithm. Unfortunatelly C++'s exception handling also has its problems. Anyway, my point was that proper error handling in the above case is pretty unnecessary IF the file is the program's own data file, and can be expected to be there on the user's machine.
Cornelius Scarabeus
What if there's a harddrive failure? What if the user deleted the file? What if the use copied the .exe, but didn't copy the data file as well? I'd prefer the programs I use to handle that sanely (not necessarily elegantly). For example, terminating the process would be perfectly acceptable. Just continuing on without reacting to the error at all is not, because it may lead to unforeseen bugs and unexpected behavior.
jalf
What if there is a memory error? There are limits to what is reasonable.
Cornelius Scarabeus
@Cornelius: See my update. Its seems that the site contractors finally agree with most of us.
ereOn
+2  A: 

You are right indeed. As other people have already pointed out, assert() will be more than likely compiled out in the release build (I've seen people force the asserts to be left in for the release build).

I just wanted to add a horror story related to this question that I've seen on a code-base:

assert(do_something() == NO_ERR);

Some people should not be allowed to use a keyboard.

Dysaster
True. Although it depends on what do_something() does. if do_something() is really do_complex_validation_that_system_state_is_valid() then it *might* be reasonable if it has no side effects
John Burton