Why I Started Using This Tool
With build, deploy, and F5 debugging all working, it was finally time to write application code. The
first task I wanted was a simple heartbeat, and its header needed a thread handle, an on/off flag, an
interval, and a return code. That's where I hit the first question: what type is each of those? Plain
int is "whatever size this compiler likes", and I didn't want to guess. So before any task,
I wrote one small shared header, types.h, that every other file in the project includes.
What It Does
Here's the whole file:
#ifndef TYPES_H
#define TYPES_H
#include <stdint.h>
typedef int32_t INT32;
typedef uint32_t UINT32;
typedef uint8_t BOOLEAN;
#define TRUE 1
#define FALSE 0
#endif /* TYPES_H */
The include guard
#include literally copy-pastes a header into your file. Since almost every file will include
types.h, sometimes indirectly through another header, it's easy for it to get pasted in twice,
and then the compiler complains that INT32 is defined twice. The guard reads like this: "if
TYPES_H isn't defined yet, define it and keep going. If it already is, skip everything down to
#endif." The first include gets the content, and every one after that gets nothing. The name
is just a convention: the file name in capitals with . turned into _.
Exact sizes from <stdint.h>
<stdint.h> is the standard header that gives you exact-size integers:
int32_t is always 32 bits and signed, uint32_t is always 32 bits and unsigned,
and uint8_t is always 8 bits, on every compiler. That matters in embedded work, where you
often care exactly how many bits a value takes, for example when it maps onto a hardware register.
Why my own names on top
INT32, UINT32, and BOOLEAN aren't part of C. They're just shorter
aliases for the stdint.h types, in a style you see a lot in embedded code: the size is right
there in the name, in capitals, so it stands out when you read a struct. If you prefer the plain
uint32_t names, that's completely fine. The important part is using exact-size types
consistently, not what you call them.
BOOLEAN, TRUE, and FALSE
BOOLEAN is a one-byte unsigned value, with TRUE and FALSE as
1 and 0. Modern C also has bool from <stdbool.h>,
which would work too. I went with the explicit one-byte type so I know exactly how big it is. One habit
worth keeping: test a flag with if (flag), not if (flag == TRUE), because any
non-zero value counts as true in C.
Where it gets used next
The very next header, swalive.h for the "SW is alive" task,
includes "types.h" for its running flag, its interval, and its return code.
Quotes in the include mean "look in my project folder first", unlike the angle brackets on
<stdint.h>, which mean "a system header".
Final Verdict
It's the smallest file in the project, but it's the one everything else stands on. Every struct and
function signature from here on says exactly how big its values are, and the include guard means any
file can include it without worrying about who included it first. If you're starting an embedded C
project, I'd write this header before anything else. It takes two minutes and saves you from ever
wondering how big an int is on your board.