Skip to content

Instantly share code, notes, and snippets.

@codeslinger
Created June 26, 2017 13:46
Show Gist options
  • Save codeslinger/d681af2b96e52ac8c276350597259dcd to your computer and use it in GitHub Desktop.
Save codeslinger/d681af2b96e52ac8c276350597259dcd to your computer and use it in GitHub Desktop.
Tagged unions (a.k.a variants) in C
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#define var __auto_type
#define let __auto_type const
static inline void * variant_cast(void * variant_ptr, ptrdiff_t desired_tag) {
ptrdiff_t * variant_tag = (ptrdiff_t *)variant_ptr;
assert(*variant_tag == desired_tag);
return (void *)((char *)variant_ptr + sizeof(ptrdiff_t));
}
#define tag(x) ((ptrdiff_t)&Tag##x)
#define is(x, T) ((x)->tag == tag(T))
#define as(x, T) ((struct T *)variant_cast((void *)(x), tag(T)))
struct SomeOne {
int x;
int y;
} TagSomeOne;
struct SomeTwo {
float z;
float w;
} TagSomeTwo;
struct Some {
ptrdiff_t tag;
union {
struct SomeOne _;
struct SomeTwo __;
};
};
int main() {
struct Some a = {};
a.tag = tag(SomeTwo);
printf("Is `a` tagged as SomeTwo: %d\n", is(&a, SomeTwo));
let b = as(&a, SomeTwo);
b->w = 5.0;
printf("b->w: %f\n", b->w);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment