//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);