Skip to content

Instantly share code, notes, and snippets.

@Rhomboid
Last active December 22, 2023 21:09
Show Gist options
  • Save Rhomboid/8e48620badbb3d9b4c30 to your computer and use it in GitHub Desktop.
Save Rhomboid/8e48620badbb3d9b4c30 to your computer and use it in GitHub Desktop.
X-Macros for serialization of C structs
#include <stdio.h>
#include <stdint.h>
typedef enum {
enOne,
enTwo,
enThree,
invalidMax = 2147483647
} MyEnum;
// automatically define a struct and its reader and writer functions simultaneously
// typedef { ... } MyStruct;
// void fread_MyStruct(MyStruct *obj, FILE *fp) { ... }
// void fwrite_MyStruct(MyStruct *obj, FILE *fp) { ... }
#define SERIALIZABLE_STRUCT_NAME MyStruct
#define SERIALIZABLE_STRUCT_MEMBERS \
SERIALIZABLE_STRUCT_MEMBER(MyEnum, anEnum) \
SERIALIZABLE_STRUCT_MEMBER(uint8_t, aChar) \
SERIALIZABLE_STRUCT_MEMBER(float, aFloat)
#include "serializable-struct.h"
// repeat as many times as necessary
#define SERIALIZABLE_STRUCT_NAME AnotherStruct
#define SERIALIZABLE_STRUCT_MEMBERS \
SERIALIZABLE_STRUCT_MEMBER(int, foo) \
SERIALIZABLE_STRUCT_MEMBER(double, bar) \
SERIALIZABLE_STRUCT_MEMBER(short, baz)
#include "serializable-struct.h"
int main(void)
{
MyStruct s;
s.anEnum = enTwo;
s.aChar = 4;
s.aFloat = 3.14f;
FILE *fp = fopen("output.dat", "wb");
fwrite_MyStruct(&s, fp);
printf("file size: %ld\nstruct size: %zu\n", ftell(fp), sizeof(MyStruct));
fclose(fp);
}
#define SERIALIZABLE_STRUCT_MEMBER(type, identifier) \
type identifier;
typedef struct {
SERIALIZABLE_STRUCT_MEMBERS
} SERIALIZABLE_STRUCT_NAME;
#define SERIALIZABLE_STRUCT_MAKENAME(functype, structname) \
functype ## _ ## structname
#define SERIALIZABLE_STRUCT_DECLAREFUNC2(functype, structname) \
static inline void SERIALIZABLE_STRUCT_MAKENAME(functype, structname) \
(structname *obj, FILE *fp)
#define SERIALIZABLE_STRUCT_DECLAREFUNC(functype) \
SERIALIZABLE_STRUCT_DECLAREFUNC2(functype, SERIALIZABLE_STRUCT_NAME)
#undef SERIALIZABLE_STRUCT_MEMBER
#define SERIALIZABLE_STRUCT_MEMBER(type, identifier) \
fread(&(obj->identifier), sizeof(type), 1, fp);
SERIALIZABLE_STRUCT_DECLAREFUNC(fread) {
SERIALIZABLE_STRUCT_MEMBERS
}
#undef SERIALIZABLE_STRUCT_MEMBER
#define SERIALIZABLE_STRUCT_MEMBER(type, identifier) \
fwrite(&(obj->identifier), sizeof(type), 1, fp);
SERIALIZABLE_STRUCT_DECLAREFUNC(fwrite) {
SERIALIZABLE_STRUCT_MEMBERS
}
#undef SERIALIZABLE_STRUCT_MEMBER
#undef SERIALIZABLE_STRUCT_DECLAREFUNC
#undef SERIALIZABLE_STRUCT_DECLAREFUNC2
#undef SERIALIZABLE_STRUCT_MAKENAME
#undef SERIALIZABLE_STRUCT_MEMBERS
#undef SERIALIZABLE_STRUCT_NAME
file size: 9
struct size: 12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment