Return codes

Exception handling

//C has no exceptions: a function returns the result of its work,
//and the value itself goes out through a pointer
typedef enum {
    PARSE_OK,
    PARSE_EMPTY,
    PARSE_NOT_A_NUMBER,
    PARSE_OUT_OF_RANGE,
} ParseResult;

//[[nodiscard]] (C23): the compiler warns if the result is ignored
[[nodiscard]] ParseResult parseAge(const char *text, int *age) {
    if (*text == '\0') {
        return PARSE_EMPTY;
    }
    char *end;
    long value = strtol(text, &end, 10);
    if (*end != '\0') {
        return PARSE_NOT_A_NUMBER;
    }
    if (value < 0 || value > 150) {
        return PARSE_OUT_OF_RANGE;
    }
    *age = (int)value;
    return PARSE_OK;
}

const char *resultNames[] = {
    [PARSE_OK] = "PARSE_OK",
    [PARSE_EMPTY] = "PARSE_EMPTY",
    [PARSE_NOT_A_NUMBER] = "PARSE_NOT_A_NUMBER",
    [PARSE_OUT_OF_RANGE] = "PARSE_OUT_OF_RANGE",
};

int age = 0;
ParseResult result1 = parseAge("42", &age);
//result1 is PARSE_OK, age is 42

//on failure the value is not touched
ParseResult result2 = parseAge("4x2", &age);
//result2 is PARSE_NOT_A_NUMBER, age is 42
ParseResult result3 = parseAge("200", &age);
//result3 is PARSE_OUT_OF_RANGE, age is 42

//the caller checks the result right after the call
if (parseAge("", &age) != PARSE_OK) {
    printf("no age given\n");
}
//printed "no age given"

//the library uses the same idea: fopen and malloc return nullptr,
//POSIX functions return -1, and errno tells the reason

printf("result1 is %s\n", resultNames[result1]);
printf("result2 is %s\n", resultNames[result2]);
printf("result3 is %s\n", resultNames[result3]);
printf("age is %d\n", age);