Error Helpers in C

I’ve been writing a lot of C lately for a game I am working on. I am not a perfect programmer and I would like to catch my bugs before they arise. Thus, I am attempting to learn Rust in my free time.


Printing a backtrace in C is not incredibly difficult to accomplish. Although the following is fairly primitive, it will aid in your ability to discern what is happening in your program

/// @file core/backtrace.c
#include <execinfo.h>
#include "backtrace.h"

/// @brief Prints a backtrace of up to the last 256 calls
/// @param [out] fd The file descriptor ID to write to
void print_backtrace(int fd) {
    void* array[256];
    size_t size = backtrace(array, 256);
    backtrace_symbols_fd(array, size, fd);

The output will look like the following


As you can see, in a method test_block_insertion I call print_backtrace. This is incredibly helpful if you need to determine how deep in the program your issue occurred.


I’ve been tinkering with Rust in my free time to get a better understanding of it and I have come to enjoy the panic! macro it employs. I like the verb and decided that it would work perfectly in my daily use.

With some alterations, I just wanted panic to do exactly what its name suggests, I want the program to panic with a message and abort.

/// @file core/panic.h
#pragma once

#include <stdlib.h>
#include <stdio.h>
#include "backtrace.h"

#ifdef NDEBUG
#define panic(message)
/// @brief Causes the program to abort and print a message
/// @param [in] message The error message you wish to spit out to stderr.
#define panic(message)                                               \
    do {                                                             \
        fprintf(stderr, "panicked at: %s:%d\n", __FILE__, __LINE__); \
        fprintf(stderr, "--> %s %s\n", message);                     \
        fprintf(stderr, "--> STACKTRACE START\n");                   \
        print_backtrace(2);                                          \
        fprintf(stderr, "--> STACKTRACE END\n");                     \
        fflush(stderr);                                              \
        abort();                                                     \
    } while (0)

Example usage would be like this

int some_function(uint8_t* data, size_t length) {
  if (length == 0) {
    panic("Zero length buffer provided!");

  // consume data

  return 1;

Output from this macro will look like the following.

panicked at: /home/warmwaffles/code/example/rbp_test.c:173
--> message: Failed to insert the block correctly
Aborted (core dumped)

I wanted the core dump to take place so that I can inspect it if I need to. Luck favors the prepared, and I always like to be prepared.


I use assert(expr) liberally through out my code to ensure that my program operates as I intend it to. Sometimes I make a mistake and would like to be notified where it happened and how deep in the call stack it did.

Unfortunately vanilla assert(expr) does not do this. But it is a simple enough macro to override and provide a little more meta information about where it failed and why.

/// @file core/assert.h
#pragma once

#include <stdlib.h>
#include <stdio.h>
#include "backtrace.h"

#ifdef NDEBUG
#define assert(expr)
#define assert(expr)                                                                     \
    if(!(expr)) {                                                                        \
        fprintf(stderr, "assertion (%s) failed at: %s:%d\n", #expr, __FILE__, __LINE__); \
        fprintf(stderr, "--> STACKTRACE START\n");                                       \
        print_backtrace(2);                                                              \
        fprintf(stderr, "--> STACKTRACE END\n");                                         \
        fflush(stderr);                                                                  \
        abort();                                                                         \

As you can see it looks almost exactly the same as panic(message) does. However, I want the expression to be spit out into stderr so that I can see what expression failed.

assertion (1 == 0) failed at: /home/warmwaffles/code/example.c:170
Aborted (core dumped)

Found these little bits of code to be useful, and figured others would probably find it useful as well.