Next: DI.h, Previous: WITHOUT_NANA, Up: Interface
This implements the C based invariant checking code and is a replacement for ‘assert.h’. The first two macros are the normal user interface; the remainder are used for configuring the behaviour on failure, etc.
The exprn should always be true if the program is correct. If the exprn is false a message will be printed, followed by core dump.1
Checking can be enabled and disabled by using the I_LEVEL and I_DEFAULT_GUARD macros. See the definitions below for these macros for further details.
Note that exprn should have no side-effects2 since disabling checking shouldn't change your programs behaviour.
I(z != 0); x = y / z;
The opposite of ‘I’, i.e. the expression must never ever be true if the program is working properly. It is equivelant to
I(!(e))
and exists as a piece of syntactic sugar which may be helpful for complicated boolean expressions.char* strdup(char *s) { N(s == NULL); ...; }
The ‘I_LEVEL’ macro is used to globally enable and disable checking by the macros in this file. It can take on one of three values:
0
- Disable all checking. Regardless of anything else no code will be generated for
I
,N
, etc.1
- Enable checking only if the corresponding guard condition is true. The guard condition can be used to enable and disable checking at compile and run time.
2
- Enable all checking regardless of guard conditions.
I_LEVEL
defaults to1
.
The
I_DEFAULT_GUARD
is used to selectively enable or disable checking at compile or run time.
I_DEFAULT_GUARD
defaults toTRUE
, i.e. always enabled.A user would typically define
I_DEFAULT_GUARD
to be global or local variable which is used to turn checking on or off at run–time. For example:#define I_DEFAULT_GUARD i_guard > 0 extern int i_guard;
This is passed off to the
I_DEFAULT_HANDLER
and defaults to nothing, it is just some text and is intended to pass failure codes (e.g.IEH303
) or requests (e.g.HW_DEAD
) information off to the handler.
I_DEFAULT_PARAMS
defaults to nothing.
When an error is detected the
I_DEFAULT_HANDLER
will be called to handle the error. The arguments are:
exprn
- A string representation of the expression that has failed, e.g.
"I(i>=0)"
.file
- The file that this error occurred in, i.e.
__FILE__
.line
- The line number for the error, i.e.
__LINE__
.param
- An optional parameter which can be passed across which defaults to
I_DEFAULT_PARAMS
. This can be used to pass failure codes or other information from the checking code to the handler.
All of the remaining macros are used to individually override the default values defined above. Normally these macros would be used in a system wide header file to define macros appropriate for the application. For example you might use ‘IH’ to define different checking macros for hardware and software faults.
We also provide support for referring to previous values of variables in
postconditions. The ID
macro is used to create variables to
save the old state in. The IS
and ISG
macros are to
set these values.
For example:
void ex(int &r) { ID(int oldr = r); /* save parameter */ g(r); I(oldr == r); /* check r is unchanged */ while(more()) { IS(oldr = r); /* assign r to oldr */ h(r); I(oldr == r * r); } }