Skip to content
  • Best Practices & Tooling · C

Best Practices & Tooling

LearnViaNotes @learnvianotes· 3 min read

C rewards discipline. These habits and tools prevent most of the bugs covered in these notes.

Compile and test

PracticeHow
Maximum warnings-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wformat=2, and -Werror in CI
Sanitizers in debug/test builds-fsanitize=address,undefined (and thread for concurrent code)
Memory checkingvalgrind --leak-check=full ./app
Static analysisclang --analyze, clang-tidy, cppcheck, gcc -fanalyzer
Debuggergdb / lldb with -g -O0: breakpoints, bt, print, watchpoints
FuzzinglibFuzzer / AFL++ for parsers and anything taking untrusted input
Formattingclang-format — never argue about braces again
Hardening-D_FORTIFY_SOURCE=2 -O2 -fstack-protector-strong

Coding habits

A defensive pattern in one place

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char  *data;
    size_t len;
} Text;

/* returns 0 on success; on failure *out is untouched and nothing leaks */
int text_read_file(const char *path, Text *out) {
    int rc = -1;
    char *buf = NULL;
    FILE *f = fopen(path, "rb");
    if (!f) goto done;
    if (fseek(f, 0, SEEK_END) != 0) goto done;
    long size = ftell(f);
    if (size < 0) goto done;
    rewind(f);
    buf = malloc((size_t)size + 1);
    if (!buf) goto done;
    if (fread(buf, 1, (size_t)size, f) != (size_t)size) goto done;
    buf[size] = '\0';
    out->data = buf;
    out->len = (size_t)size;
    buf = NULL;                  /* ownership transferred to *out */
    rc = 0;
done:
    free(buf);                   /* free(NULL) is fine */
    if (f) fclose(f);
    return rc;
}

int main(void) {
    FILE *f = fopen("note.txt", "w");
    if (!f) return 1;
    fputs("clean C", f);
    fclose(f);

    Text t = {0};
    if (text_read_file("note.txt", &t) == 0) {
        printf("%zu bytes: %s\n", t.len, t.data);
        free(t.data);
    }
    printf("missing file -> %d\n", text_read_file("missing.txt", &t));
    return 0;
}
Output
7 bytes: clean C
missing file -> -1

Debugging workflow

Terminal
$ gcc -g -O0 -Wall -Wextra -fsanitize=address,undefined app.c -o app
$ ./app                       # sanitizer reports file:line of the first bad access
$ gdb ./app                   # or: lldb ./app
(gdb) break parse_line        # stop in a function
(gdb) run input.txt
(gdb) next / step / finish    # step over / into / out of
(gdb) print *node             # inspect memory
(gdb) bt                      # backtrace after a crash
(gdb) watch count             # stop when a variable changes

How would you debug a segmentation fault?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report