Skip to content

Instantly share code, notes, and snippets.

@taeber
Last active August 31, 2017 21:37
Show Gist options
  • Save taeber/10d670891a73631ecfae65fa71a67159 to your computer and use it in GitHub Desktop.
Save taeber/10d670891a73631ecfae65fa71a67159 to your computer and use it in GitHub Desktop.
C Metaprogramming

C Metaprogramming

Macros are used for metaprogramming in C. As an example, a generic List is typically implemented with macros, such as LIST_HEAD_INIT in the Linux kernal or LL_* in (https://troydhanson.github.io/uthash/utlist.html).

I tend to dislike macros, especially ones that emulate control structures and function-macros liberally shrewn about the code. I do like the idea of C++ metaprogramming, but it can get a bit obscure.

So, how could one emulate templates in C++ to get some of the benefits, but still keep it simple so it's not so arcane?

I started with a simple linked-list. What if I could import the same file, but have it use different types?

list.c is the start of a templated linked-list. Given a type T, it will generate the code to create a TListItem and append to the list.

In the calling module, in this case main.c you specify T (and TListItem) using #define T .... Then, include #include "list.c" and undefine T.

Why?

Basically, following a lot of #define, #include, and #undef, the code itself is free from needing to use macros and instead can make real function calls.

What do you think? Good? Bad?

Compile and Run

$ gcc main.c
$ ./a.out
42
howdy
#include <stdlib.h>
#ifndef T
static T mustBeDefined;
#endif
#ifndef TListItem
static TListItem mustBeDefined;
#endif
#define FN(name) CONCAT_MACRO(TListItem, name)
#define CONCAT_MACRO(a,b) CONCAT(a,b)
#define CONCAT(a,b) a ## b
typedef struct TListItem TListItem;
struct TListItem {
T data;
TListItem *next;
};
/* TListItemCreate() */
TListItem * FN(Create)(T data) {
TListItem *item;
item = malloc(sizeof(TListItem));
if (item == NULL) {
exit(2);
}
item->data = data;
item->next = NULL;
return item;
}
/* TListItemAppend() */
void FN(Append)(TListItem *head, TListItem *item) {
/* ... */
}
/* TListItemRemove() */
void FN(Remove)(TListItem *head, TListItem *item) {
/* ... */
}
#include <stdio.h>
#define TListItem IntListItem
#define T int
#include "list.c"
#undef T
#undef TListItem
#define TListItem StringListItem
#define T char *
#include "list.c"
#undef T
#undef TListItem
int main(int argc, char *argv[]) {
IntListItem *item;
StringListItem *sitem;
item = IntListItemCreate(42);
sitem = StringListItemCreate("howdy");
printf("%d\n", item->data);
printf("%s\n", sitem->data);
/* ... */
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment