Elevator Pitch
When using C for complex projects, the lack of generics is frustrating:
- tradeoff performance and store runtime type information (e.g. size of items in a vector)
- tradeoff usability and restrict sizes of types, use unions (e.g. vector of only 8 byte items, user must cast to their own type, debuggers unaware of real type)
- tradeoff readability & development speed by outsourcing data structure generation to another language (cmake calling python to generate headers)
- tradeoff tooling for formatting, linting & intellisense with complex preprocessor macros to generate data structures
Derive-C aims to avoid these, and to get an experience close to simple templates in C++:
- templates are edittable (with intellisense), lintable, formattable independent of their usage.
- instances of templates should be clangd friendly / show types & completions
- no performance tradeoff
- easy to debug with in GDB
For example:
Create a vector of characters '1'-'9', iterate and print them. No heap allocation & no memory leaks.
#include <stdio.h>
#define CAPACITY 2048
#define SELF alloc_2048
#define T char
#define ALLOC alloc_2048
#define SELF vec_char
alloc_2048 alloc = alloc_2048_new();
vec_char vec = vec_char_new(&alloc);
for (char x = '1'; x <= '9'; x++) {
vec_char_push(&vec, x);
}
vec_char_iter_const iter = vec_char_get_iter_const(&vec);
char const* entry;
while ((entry = vec_char_iter_const_next(&iter))) {
printf("entry: %c\n", *entry);
}
vec_char_delete(&vec);
}
Use
In a CMakeLists.txt
include(FetchContent)
FetchContent_Declare(
derive-c
GIT_REPOSITORY https://github.com/OliverKillane/derive-C
GIT_TAG <Chosen derive-c version>
)
FetchContent_MakeAvailable(derive-c)
Develop
nix-shell is included to setup the C/C++ toolchain.
nix-shell # from repo root
cmake -S . -B build -GNinja
cd build
ninja
ninja format
ninja lint-c
ninja docs
ninja coverage
ctest
Then when opening vscode from the nix-shell, the correct clangd & library paths are used:
For using infer, infer must be installed separately (it is not yet packaged with nix - see here)
- Build with clang
cmake -S . -B build -DEXTERNALS=Off
infer run --compilation-database build/compile_commands.json --bufferoverrun --liveness --pulse
infer explore
- Statically detects generic bugs (e.g. use after free, buffer overrun, integer overflow)
TODO
In development, remaining tasks:
- Fix remaining infer-detected casting issues
- Finish gdb pretty printers
- Increase coverage for hashmap
- Regression benchmarks
- compare & optimise hashmap versus: ankerl
References