Patterns#
A handful of conventions help C programs stay correct and maintainable.
Header Guards#
Prevent multiple inclusion either with the classic guard or with #pragma once:
#ifndef MYLIB_H
#define MYLIB_H
/* declarations */
#endif
Opaque Pointers#
Hide implementation details by exposing only a forward declaration in the header.
// queue.h
typedef struct Queue Queue;
Queue *queue_new(void);
void queue_free(Queue *q);
Resource Cleanup#
A single goto cleanup label keeps error paths simple:
int run(void) {
FILE *f = NULL;
char *buf = NULL;
int rc = -1;
f = fopen("data", "rb");
if (!f) goto cleanup;
buf = malloc(1024);
if (!buf) goto cleanup;
/* ... work ... */
rc = 0;
cleanup:
free(buf);
if (f) fclose(f);
return rc;
}
Return-Code Errors#
C has no exceptions. Functions return a status (0 for success, negative or
errno on failure) and write results through out-parameters.
int parse_int(const char *s, int *out);
Const Correctness#
Mark inputs that won’t be modified as const so the compiler can catch
accidental writes and the intent is clear.
size_t my_strlen(const char *s);
Defensive sizeof#
Use sizeof *p (matched to the variable, not the type) so renames stay
correct.
T *p = malloc(n * sizeof *p);