Created
November 30, 2021 06:47
-
-
Save brimonk/5f7c6258f855c57c886c37177ada20c3 to your computer and use it in GitHub Desktop.
A Small, Metaprogramming Example in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Brian Chrzanowski | |
// 2021-11-30 00:06:44 | |
// | |
// This is just a small demonstration that with the help of the C Preprocessor, and some macros, we | |
// can approach some meta programming things that get compile-time checked by the compiler. It isn't | |
// as elegant as something like Jai, but in theory, you could execute something like this at the | |
// very start of the program. | |
// | |
// If C supported more things out of the box to facilitate metaprogramming, this could could get a | |
// lot nicer, but that's what it is. | |
// | |
// OUTPUT: | |
// metadata: | |
// size: 12 | |
// fields: 3 | |
// | |
// name: i | |
// size: 4 | |
// type: int | |
// offset: 0 | |
// name: j | |
// size: 4 | |
// type: int | |
// offset: 4 | |
// name: k | |
// size: 4 | |
// type: int | |
// offset: 8 | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <stddef.h> | |
#define NameOf(x) (#x) | |
#define MemberSize(type, member) sizeof(((type *)0)->member) | |
// TestStruct : this is the actual struct you might have in the program as some "data". | |
struct TestStruct { | |
int i, j, k; | |
}; | |
// Field : defines a single field, within a structure | |
// NOTE (Brian): You could reasonably create a mapping between the text type and some enum | |
// for easier mangling in the future. | |
struct Field { | |
char name[32]; | |
char type[64]; | |
int size; | |
int offset; | |
}; | |
// Structure : this is the metadata for a single structure | |
struct Structure { | |
char *name; | |
int size; | |
struct Field fields[64]; | |
int cnt; | |
}; | |
#define ADDMETA(m,s,t,y) AddMeta(m, NameOf(y), NameOf(t), MemberSize(s,y), offsetof(s,y)) | |
void AddMeta(struct Structure *meta, char *name, char *type, int size, int offset) | |
{ | |
struct Field *field; | |
if (meta && meta->cnt < 64) { | |
field = meta->fields + meta->cnt++; | |
strncpy(field->name, name, sizeof(field->name)); | |
strncpy(field->type, type, sizeof(field->type)); | |
field->size = size; | |
field->offset = offset; | |
} | |
} | |
int main(int argc, char **argv) | |
{ | |
struct Structure metadata; | |
int i; | |
memset(&metadata, 0, sizeof metadata); | |
metadata.name = NameOf(struct Structure); | |
metadata.size = 0; | |
ADDMETA(&metadata, struct TestStruct, int, i); | |
ADDMETA(&metadata, struct TestStruct, int, j); | |
ADDMETA(&metadata, struct TestStruct, int, k); | |
for (i = 0; i < metadata.cnt; i++) { | |
metadata.size += metadata.fields[i].size; | |
} | |
printf("metadata:\n"); | |
printf("\tsize: %d\n", metadata.size); | |
printf("\tfields: %d\n", metadata.cnt); | |
printf("\n"); | |
for (i = 0; i < metadata.cnt; i++) { | |
printf("\tname: %s\n", metadata.fields[i].name); | |
printf("\t\tsize: %d\n", metadata.fields[i].size); | |
printf("\t\ttype: %s\n", metadata.fields[i].type); | |
printf("\t\toffset: %d\n", metadata.fields[i].offset); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment