13

Lately I have been struggling to understand what the right amount of checking is and what the proper methods are.

I have a few questions regarding this:

What is the proper way to check for errors (bad input, bad states, etc)? Is it better to explicitly check for errors, or use functions like asserts which can be optimized out of your final code? I feel like explicitly checking clutters a program with a lot of extra code which shouldn't be executed in most situations anyway-- and not to mention most errors end up with an abort/exit failure. Why clutter a function with explicit checks just to abort? I have looked for asserts versus explicit checking of errors and found little to truly explain when to do either.

Most say 'use asserts to check for logic errors and use explicit checks to check for other failures.' This doesn't seem to get us very far though. Would we say this is feasible:

Malloc returning null, check explictly
API user inserting odd input for functions, use asserts

Would this make me any better at error checking? What else can I do? I really want to improve and write better, 'professional' code.

6
  • 3
    Good question, but I think it might be better suited for one of the sister sites (programmers?).
    – user786653
    Oct 27, 2011 at 15:58
  • Thanks, I wasn't sure. I thought since it was pretty code-related SO would have been alright.
    – Anon
    Oct 27, 2011 at 16:22
  • 3
    The simple answer is "This is why exceptions were invented. Get a better language."
    – DeadMG
    Oct 27, 2011 at 16:42
  • 1
    @DeadMG: setjmp/longjmp are available in C, so you don't need a new language.
    – user786653
    Oct 27, 2011 at 17:05
  • 3
    @DeadMG: Someone who cannot get C error checking right has a snowballs chance in hell getting C++ exception handling right...
    – Coder
    Oct 27, 2011 at 19:01

5 Answers 5

4

The easiest way for me to tell the difference is to determine whether the error condition is introduced at compile time or run time. If the problem is a programmer using the function wrong somehow, make it an assert to draw attention to the problem, but once the fix is compiled into the calling code, you don't need to worry about checking for it any more. Problems like running out of memory or bad end user input can't be solved at compile time, so you leave the checks in.

2

Do check anything at any time (it could have changed after your last check) that is not 100% under your command. And also: During developement even do not trust yourself! ;-)

Okokok ... "anything" is meant to be read as checking for such things which would cause an abnormal abort or anything which could make your application/system do things it should not do.

To be serious, the last part of the last sentence is essential because it points to the main issue:

If you want to build a stable system the main concern it not about what the system should do, but to let it be able to do such mandatory things, one needs to take care of what it should not do, even if it "clutters your code".

1
  • 1
    +1 for 'check everything'. I don't buy the argument of code clutter: any programmer should be able to distinguish between error checking and actual logic anyway.
    – stijn
    Oct 27, 2011 at 18:02
2

The crux of the error handling is not whether and how you catch the trouble. It is more of what you do after you learn about it.

First off - i would say, there is no reason why any single error returned by subordinate method is returning shouldn't be handled. And errors and exceptions are just more than the return values or all try/catch.

  1. Just throwing and catching is not enough.
    See this : where the author explains that just by catching but doing nothing potentially suppresses the exception and unless enough is done to undo the damage - it is worse than letting the code go just like that. Similarly just writing "log" statement when there is a file open or read error might help find the reason why - but by the time program terminates, it might have caused the data to go damage! It is not enough to say i have many try/catch - it is more important to know what they really do!

  2. Don't abuse the try and catch.
    Some times - mostly lazy or naive programmers think that after writing sufficient try/catch, their job is over and easy. Quite often it is best to apply corrective action and resume rather than just dump the whole thing. If this cannot be done, one needs to decide at what level you need to go back. Depending on the context and severity, try catch nesting needs careful design. For example- See this and this

  3. Define who is responsible:
    One of the first thing you should do is to define whether the input given to the routine itself is just an unacceptable (or not-handled so far) scenario or is the exception due to environment (such as system issue, memory issue), or is this situation a completely internal arising out of algorithm outcome. In all cases - the level at which you may want to go back to or action you want to take differs significantly. In this light i would like to say - that when you run the code in production - making abort() to exit the program is good - but not for every small thing. If you spot memory corruption or out of memory it is definite that even after doing your best - things will die. But if you receive a NULL pointer at the input - i wouldn't go on calling abort() -i would rather send it back to the caller with an error and see if she is smart enough to figure out whether it can correct itself.

  4. Define what is the best possible outcome:
    What all things must be done under exception is very critical. For example if in one of our cases - a media player finds that it doesn't have full data that to be played out to user - what is it should do?

    • either skip some bad part and see if it can get ahead with good things.
    • if this happens too much consider if it can skip to next song.
    • if it finds that it is not able to read any file - stop and show something.
    • in the meanwhile
    • under which of the state should a player POP-UP to the user and
    • when should it carry on its own?
    • Should it "halt" things to ask user feed back
    • or should it put unobtrusive little error note in some corner?

    All these are subjective - and perhaps there are more ways to handle problems than we trivially thing. All of the above requires to build and understand depth of the exception and than also make different scenarios should be possible to evolve to.

  5. Sometimes we need to check for exceptions before they arise. The most common example is the divide by zero error. Ideally one must test that before such exception is thrown upon - and if that is the case- try to put most appropriate non-zero value and move on rather than go suicide!

  6. Clean-up. At least this is what you must do! If a function happens to open 3 files and fourth one fails to open - needless to say the first 3 should have been closed. Delegating this job to a layer above is a bad idea. if you decide to quite don't leave without cleaning memory. And most important - even if you have survive the exception, do inform the higher up that things haven't took the normal course.

The way we see (normal) functionality of the software in terms of various hierarchies or layers or abstractions, same way we must categorize exceptions based on their severity as well as scope under which they arise and they are affecting other parts of system - that defines how to handle such different exceptions in best possible way.

Best reference: Code Craft chapter 6 - available for download

1

Checking errors during debug builds only is a BAD IDEA(tm), compiling under release overlays reusable variables on stack, removes guard pages, does iffy tricks with calculations, replaces heavy arthritics with precomputed shifts and so on.

Use error checking in release as well, you can resort to something as simple as:

if(somethinghitthefan)
     abort();

This also has a very good side effect that you definitely won't ignore the bug once the application starts crashing on betta testers PC.

Event viewers and logs are completely useless compared to abort(), who checks them anyway?

3
  • exit/abort == worst user experience ever: the application just disappears without telling why..
    – stijn
    Oct 27, 2011 at 19:15
  • @stijn: abort breaks into debugger/creates a dump. exit is bad, yes. Although, I prefer __asm int 3 the most.
    – Coder
    Oct 27, 2011 at 19:18
  • that is true, and in C/C++ I tend to write asserts using __asm int 3 as well, but never without showing at least a description of why, and preferrably also line and file. Then at least the customer can give info about what happened exactly.
    – stijn
    Oct 28, 2011 at 6:35
0

The various things that you can do is
1.Read and assimilate lot of code online and see how it is done
2.Use some debugging tools so as to help you locate regions of errors
3.Be aware of trivial errors due to improper assignments and syntax errors.
4. Some worse errors arrise due to logical errors in the program which are harder to find .For this you can pen it out and find or for more complicated ones try speaking to people or use resources like Stackoverflow, Wikipedia, google to get help from people.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.