2025-10-18

return status and error handling

part of c programming

  • it is possible to use a status variable with an object that stores a status id and group id. this object can be checked for a failure status, and goto can be used to jump to an exit label at the end of the routine where all cleanup is done. gotos in c are local to the current routine. it is a bit like local exceptions
  • the status id represents an error code or general status code, the group id is a string name of the library the code belongs to. when multiple libraries are used, it would otherwise be almost impossible to synchronize error codes so that they are not ambiguous. string names are used because integer ids would again be hard to keep unambiguous
  • doing all clean-up at the end of the routine can save code duplication. it can be useful to set variables to null values before they have been used so that the clean-up part can know, for example, what memory to free

example

  • this example uses a reference implementation from sph-sc-lib
  • status_declare declares a local variable status_t status = {0, ""};, the other status_* bindings use that variable
  • status_require checks that status.id is status_id_success, which is zero, and goes to exit if not
  • this is compatible with common error handling using int error codes, where 0 means no error
#include "sph/status.c"

status_t test() {
  status_declare;
  if (1 < 2) {
    status_set_goto("mylib", 456);
  }
exit:
  return status;
}

int main() {
  status_init;
  // code ...
  status_require(test());
  // more code ...
exit:
  return status.id;
}

example implementation

#ifndef sph_status_h
#define sph_status_h

/* return status as integer code with group identifier
for exception handling with a local variable and a goto label
status id 0 is success, everything else can be considered a special case or failure
status ids are signed integers for compatibility with error return codes from other existing libraries
group ids are strings, used to categorise sets of errors codes from different libraries for example */
#include 
typedef struct {
  int id;
  uint8_t* group;
} status_t;
#define status_id_success 0
#define status_group_undefined ((uint8_t*)(""))
#define status_declare status_t status = { status_id_success, status_group_undefined }
#define status_is_success (status_id_success == status.id)
#define status_is_failure !status_is_success
#define status_return return (status)
#define status_i_return return ((status.id))
#define status_goto goto exit
#define status_set(group_id, status_id) \
  status.group = ((uint8_t*)(group_id)); \
  status.id = status_id
#define status_set_goto(group_id, status_id) \
  status_set(group_id, status_id); \
  status_goto
#define status_require(expression) \
  status = expression; \
  if (status_is_failure) { \
    status_goto; \
  }
#define status_i_require(expression) \
  status.id = expression; \
  if (status_is_failure) { \
    status_goto; \
  }
#define status_require_return(expression) \
  status = expression; \
  if (status_is_failure) { \
    status_return; \
  }
#endif

more

error handling in general