Lesson content
Read, practise, then check your understanding
C has no exception mechanism. Functions report failure through return values, output parameters, status enums, and occasionally errno. A reliable program checks failures where they occur and preserves enough context to diagnose them.
Return-value contracts
Choose one unambiguous convention and document it.
enum ParseResult {
PARSE_OK,
PARSE_INVALID,
PARSE_OUT_OF_RANGE
};
enum ParseResult parse_port(const char *text, unsigned *port);
Separate status from output so every valid output value remains representable. Do not ignore functions whose return value reports a short write, failed close, or partial operation.
errno
Some library and system functions set errno after failure. Include <errno.h>, check the function’s documented failure result first, and then inspect errno promptly.
errno = 0;
char *end = NULL;
long value = strtol(text, &end, 10);
if (end == text) {
/* no digits */
} else if (errno == ERANGE) {
/* outside long range */
} else if (*end != '\0') {
/* unexpected suffix */
}
Do not test errno after success; successful functions need not clear an old value. perror and strerror provide human-readable messages, while production logs should also retain operation and input context without leaking secrets.
Cleanup paths
When a function owns multiple resources, acquire in order and release in reverse. A forward goto cleanup keeps each failure path correct and avoids deeply nested blocks.
int transform(const char *path) {
int status = -1;
FILE *file = fopen(path, "rb");
unsigned char *data = NULL;
if (!file) goto cleanup;
data = malloc(4096);
if (!data) goto cleanup;
status = process(file, data);
cleanup:
free(data);
if (file && fclose(file) != 0 && status == 0) status = -1;
return status;
}
Assertions and recovery
assert documents internal conditions that indicate programmer defects. It may disappear under NDEBUG, so never use it to validate external input or perform required side effects. Recoverable failures should return a status; impossible internal states may justify an assertion or controlled termination.
Test error paths deliberately, including allocation failure, truncated input, permission errors, and cleanup after partial initialization.
Knowledge check
Answer every question correctly to complete this chapter.
0 of 10 checks passed
Your progress is saved on this device.