I too am a fan of errchk and nullchk and have made some additions to them.
The first one is to redefine the macros to save the line on error in a variable (I'm using here the macro __LINE__ included in the compiler).
The second is to create other sets of macros for DAQ acquisition, serial communications and file I/O with the same structure but different variable for storing the error (I called them ioerr, comerr and daqerr).
That way, I can have only one Error label in a rountine that uses all of them: on Error label I can easily discriminate the error encountered by testing the different xxerr variables and take the appropriate countermeasures. Something like this (limiting in this case to warn the operator):
Error:
if (error < 0) {
sprintf (msg, "Error %d found in %s (line %d):\n%s.", error, __FUNCTION__, line, GetGeneralErrorString (error);
}
else if (daqerr < 0) {
sprintf (msg, "Error %d found in %s (line %d):\n%s.", error, __FUNCTION__, line, GetNIDaqErrorString (daqerr);
}
else if (ioerr) {
// Here is a little more complicated since file I/O functions don't share the same error list.
}
else if (comerr < 0) {
sprintf (msg, "Error %d found in %s (line %d):\n%s.", error, __FUNCTION__, line, GetRS232ErrorString (comerr);
}
BTW, I found very useful in this respect the macro __FUNCTION__ that returns the present rountine name: I discovered it here in the forum.
The last addition is a macro useful in DAQ acquisition: I created a macro called DaqOut that basically is a copy od daqChk but instead of jumping to a lable simply issues a break statement. I use it when I am in a while loop during a data acquisition: in the loop I usually take some measures with DAQ_Monitor to check the phenomenon: in case of error the macro exits the loop and goes to a daq_clear located immediately outside it to stop the acquisition in progress.