specification of a c status-return convention and a centralized cleanup pattern compatible with it.
the convention defines:
status_ttypedef struct {
int id;
const char* group;
} status_t;id == 0 denotes successid != 0 denotes failuregroup identifies the namespace defining idcanonical success value:
{ .id = 0, .group = "" }a status is identified by the pair:
(group, id)
each fallible function:
status_tid == 0 on successid != 0 on failuregroup to the namespace that defines the returned ida function may declare:
status_t status = {0, ""};and return that variable at any return site.
multiple return statements are permitted.
given:
status = callee(...);
if:
status.id != 0
the caller determines control flow based on that condition and may propagate the same status value.
propagation preserves both group and id unless explicitly reassigned.
for a function returning an integer error code:
int code = other_function(...);
lift into a status value:
status.id = code; status.group = "";
where:
code == 0 denotes successcode != 0 denotes failurea function that manages resources may define a labeled region:
exit:
control flow may transfer to this region when a failure condition is detected.
normal execution may also reach this region.
for resources that require cleanup on failure:
the method used to encode prepared versus non-prepared state is implementation-defined.
at exit::
status valuea module conforms when:
status_tid == 0 as the success indicator(group, id) as the failure identifierstatus.id#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;
}status.h
#ifndef sph_status_h_included #define sph_status_h_included /* 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 */ #includetypedef struct { int id; char* group; } status_t; #define status_id_success 0 #define status_group_undefined "" #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 = 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
error handling in general