| TRY | Language Extension |
| error.h |
Starts a protected block of code.
TRY,
ONERR,
ENDTRY,
FINALLY,
ENDFINAL, and
PASS
are macros which extend the C language to implement an error handling mechanism which is
almost identical to the commonly-used exception handling as well as error handling in TI-Basic.
TRY begins the protected block. It is a macro which is implemented using the
ER_catch function. If an error occurs in the protected block, program
execution transfers to the block after the ONERR or
FINALLY statement.
However, ONERR and FINALLY
are entirely different. The ONERR block will not
be executed if there was no error, and it is assumed to either handle the
error or call PASS. The error is cleared, so if
PASS is not called, the execution continues
normally after the ENDTRY statement.
FINALLY, on the other hand, is not implemented
to handle errors, but instead to create a block of code which will always be
executed, regardless of whether there was an error or not. It does not clear
the error (or more precisely, ENDFINAL throws
it again). This can be used in a function which allocates memory, destroys
the contents of the screen, or does something else which always needs cleaning up.
If the function throws an error in a protected block, the memory should
always be freed again, the screen should be restored, etc. But the error
should not be handled at the same time; instead, it must be handled on a
higher level (often even in the calling function).
The usage of ONERR is illustrated in the following example:
TRY
// <protected code>
ONERR
if (errCode == some_specific_code)
// <error handler>
else
// pass on any unhandled errors to a higher level
PASS;
ENDTRY
The usage of FINALLY is illustrated in the following example:
TRY
...
// <allocate memory>
TRY
// <protected code>
FINALLY
// <free the allocated memory>
ENDFINAL
...
ONERR
// <error handler>
ENDTRY
The variable errCode is automatically created in the error handler, and
it contains the error number to allow the program to check what caused the error. This variable
will be destroyed after the ENDTRY/ENDFINAL statement.
TRY
...
if (I_really_must_exit_from_here)
{
ER_success ();
return;
}
...
ONERR
...
ENDTRY
But in general this is a very bad practice and should be avoided even if it
requires some extra code. For example, you can rewrite the code like this:
TRY
...
if (!I_really_must_exit_from_here)
{
...
}
ONERR
...
ENDTRY
if (I_really_must_exit_from_here)
return;
There is also another possible caveat related to error handling. The TRY macro (or
ER_catch, more precisely) saves many of
the registers on its execution context stack, since ER_catch needs to
simulate a return identical to the return of any normal function. Consequently, when an error is thrown, all
variables which reside in registers are reset to their contents before the TRY macro was
called. If code in an ONERR or FINALLY
block needs the value of a variable set in the TRY block, the code must arrange to make sure
the C code optimizer does not put that variable in a register. This can be
accomplished by declaring such variables to be volatile.
So, remember this rule: Variables changed in a TRY block must be declared volatile if they
are referenced in an ONERR or FINALLY block!
ENABLE_ERROR_RETURN instead of using a
TRY...ONERR...ENDTRY block.
See the section Returning Errors
for more information.