my prelude.h for C coding
customize your environment to bring joy to programming
I’ve recently started using a prelude.h include file to customize how
my C projects look and feel. If you’ve read the last couple of posts
featuring C code you’ve probably noticed the types look a bit… Rusty. A
long time ago I did an experiment, writing a text editor in a very
dense obfuscated style. It was a mess, and I did end up reverting to
a more normal style. One thing I did really like was having
more concise standard types. In that project int was
i, char was c, etc. That’s too
much. I’ve settled on nice Rust-style types. I include typedefs for
those, a bunch of include boilerplate I use in almost every project, and
a growing collection of utility functions into one header file and
started using it everywhere.
easy project setup
I’ve written before about unity
builds as a way to make setting up a project easier. The
prelude.h extends that simple setup to my includes. It’s a
small thing, but it’s nice not having to keep a big include list up to
date. If it’s some boilerplate I’m almost always using, just throw it in
prelude.h.
It’s also a great home for small utility functions and macros. I have
a sequal function that does strcmp() == 0. I
have a swap, and an ease. All tiny things that
are just nice to have everywhere. I’m sure I’ll end up with
pick and slurp at some point, but I haven’t
added them yet.
typedef int bool;
#define true 1
#define false 0
// Simple assert macro; prints to stderr and then aborts.
#define assert(c, msg) do { if (!(c)) { fprintf(stderr, "%s\n", msg); abort(); }} while(false)
typedef uint8_t u8;
typedef int32_t i32;
typedef uint32_t u32;
typedef uint64_t u64;
typedef float f32;
typedef double f64;
typedef char byte;
typedef ptrdiff_t size;
typedef size_t usize;
typedef char* str;
static f32 ease(f32 current, f32 target, f32 speed, f32 dt)
{
return current + (target - current) * (1 - exp(-speed * dt));
}
It’s nice to build up a list of utilities that work the way
I want them to, and that I can hack up easily. I
love hopping around to different programming languages all the time but
I feel like one of the big downsides of that is that I don’t have my own
set of utilities that get copied into every project. Now that I’m
starting to consciously work on that for my C projects I wish I had done
it sooner!
small editor
customizations are neat too
Another little trick I did was customize my C syntax highlighting in
vim. To force myself to use the new types, I added syntax highlighting
that underlines them in red. I’d keep typing int32_t and
such out of habit, but now the syntax highlighter yells at me. All of my
new typedefs get highlighted like they’re builtins.
Lately I have been trying to avoid using unsigned ints as much as
possible. Sometimes you need to use them, but in C comparing signed and
unsigned integers is fraught with peril. I’ve had way too many infinite
loops turn out to be due to bad signed vs unsigned comparisons, and one
of the nastiest bugs I’ve seen in production was caused by it. So now I
try to just avoid unsigned where I can. I made the syntax highlighter
show unsigned types with a yellow underline. It really draws attention
to them and makes me double check to ensure they’re really needed. I
think in all of the C I’ve written this year I’ve only really needed
u32 for my xorshift RNG.
" .vim/after/syntax/c.vim
" custom typedefs from prelude.h
syntax keyword cType u8 i32 u32 u64 f32 f64 byte size usize str
" old types that are overridden by prelude types
syntax keyword cOldType int double float size_t ptrdiff_t
syntax keyword cOldType uint8_t uint32_t uint64_t int32_t
syntax keyword cOldType long short unsigned signed
highlight cOldType ctermfg=Red cterm=underline guifg=Red gui=underline
" yellow underline for unsigned typedefs
syntax keyword cUnsignedType u8 u32 u64 usize
highlight cUnsignedType ctermfg=Yellow cterm=underline guifg=Yellow gui=underline
For side projects you really can’t beat customizing stuff. I’m
starting to think for larger projects and for corporate work it’s making
more and more sense to have a mostly in-house standard library as well.
There was recently a supply chain attack in the Rust ecosystem,
targeting the arrayref crate. I think the macros in
question are a great candidate for dropping into a
prelude.h type of library within your project / company
instead of bringing in a dependency. And I think it’s the kind of
dependency crate authors need to avoid to help keep transitive
dependencies clean.
As a younger engineer I learned in an environment where avoiding “Not
Invented Here” syndrome was considered very important. Don’t reinvent
the wheel, library authors will catch way more bugs and you’ll benefit
from their fixes. But over the years I think supply chain risk has
undermined that quite a bit, and a lot of very highly touted libraries
turn out to be not so great if you start reading the code.
And sometimes making wheels is fun.