How do you do metaprogramming in C?

At one point Casey mentioned that he was doing metaprogramming in C and his response was


I just write C programs that spit out C programs. My compilation is
always two-phase: first it builds a C program, then runs it, then it
compiles the output.

This was a little bit too broad for me but I didn't want to bother him again, I am sure he has more important things to do.

But maybe some of you guys know what he means?

I am already aware of macros and the preprocessor and I think there are now variadic macros in c11? So I am sure that one could use those to create some sort of metaprorgramming framework but I think Casey is doing it a little bit different.

In my head it looks like this:

1
2
std::string foo_class = "class Foo { int bar, int baz};"
writeTofile("Foo.h",foo_class");


But working with string seems a little bit cumbersome. How do you do metaprogramming in C? I couldn't find many resources on this topic.
That's pretty much what I am talking about. Imagine you're on your fourth generation of programming that way, and what that looks like, and that's basically what I do. You create actual data structures for storing program structure, though, you don't just use strings.

It's the only sane way to program, currently. Modern languages are so poorly designed that they hinder you more than they help when you are trying to actually program at a high level if you care about what the results are at the low level, which I do.

- Casey
Well, you don't.
What you can do is working with macros, but that is a nightmare.
If you like sane Templates I really encourage you to try D.
a template in D looks like this:

T min(T)(T a, T b) {
return (a<b?b:a);
}
The other D language feature that makes metaprogramming possible without leaving the language (ie, making Makefiles or shell/batch scripts that have a step to build code and then another to compile the built code), but which makes my head hurt while there isn't yet any sane debugability (that I know of), is CTFE - compile time function execution.

I somewhat randomly explored that topic last year - here's what I did to make compile-time checked (with no casting) access to OpenGL uniforms in a little side project (and shows off templates to some degree too) - http://play.techgeneral.org/mixins-and-other-code-generation.html

(Note that I don't know D, OpenGL, or game programming remotely well enough to give any advice - I just like to explore new things.)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#define SWAP(T,A,B) {T _tmp = A; A=B; _tmp=A;}
//T is the Type A and B have;
int a = 14;
int b = 42;
SWAP(int,a,b);
assert(a == 42);
assert(b == 14);
SWAP(int,a,b);
assert(a == 14);
assert(b == 42);


There you go :)

This is equvalent to a roughly template (-type deduction)

Edited by Stefan Koch on
@Casey If you ever feel like writing something -- or shooting a video -- on the subject, I'd be very interested. I don't think I'd be the only one either :)

Even a release of some crappy non-ironed out code would be interesting; to get a sense of the ideas.
Are there any libraries or code samples or other sources we can check out to learn some of this stuff? I'm very interested in it as well and would like to see some good examples of how metaprogramming is done in c.
The clang developers have an extremely interesting technique for metaprogramming which may be worth considering.

In my compiler, I need to implement a bunch of unary operators. I want an enumeration for them, but there's also other stuff I might want to do with the same list of operators.

How can I do this?

First, I'll put all of the data in one file, which I call unary_operators.inc:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
UNARY_OPERATOR(uo_post_inc, "++")
UNARY_OPERATOR(uo_post_dec, "--")
UNARY_OPERATOR(uo_pre_inc, "++")
UNARY_OPERATOR(uo_pre_dec, "--")
UNARY_OPERATOR(uo_ref, "&")
UNARY_OPERATOR(uo_deref, "*")
UNARY_OPERATOR(uo_plus, "+")
UNARY_OPERATOR(uo_minus, "-")
UNARY_OPERATOR(uo_b_not, "~")
UNARY_OPERATOR(uo_l_not, "!")
UNARY_OPERATOR_COUNT(uo_count)
#undef UNARY_OPERATOR
#undef UNARY_OPERATOR_COUNT


The reason for the undefs will become clear soon. Now, if I need the enumerated type, I can do this:

1
2
3
4
5
enum unary_operator_t {
#define UNARY_OPERATOR(t,s) k_##t,
#define UNARY_OPERATOR_COUNT(t) k_##t
#include "unary_operators.inc"
};


Or perhaps I want to be able to resolve them as strings:

1
2
3
4
5
6
const char*
sUnaryOperatorNames[] = {
#define UNARY_OPERATOR(t,s) s,
#define UNARY_OPERATOR_COUNT(t) #t
#include "unary_operators.inc"
};


Game engines often have custom metaobject protocols because neither C nor C++ have one that is in any way suitable. This is one way to do it which avoids the multiple-maintenance problem and also avoids the need for a separate tool.
norswap
@Casey If you ever feel like writing something -- or shooting a video -- on the subject, I'd be very interested. I don't think I'd be the only one either :)

I already have my hands full with the Handmade streams, so I don't think something like that's going to be on the table for a long time...

- Casey
So will you plan to do some metaprogramming for HMH?
cmuratori
That's pretty much what I am talking about. Imagine you're on your fourth generation of programming that way, and what that looks like, and that's basically what I do. You create actual data structures for storing program structure, though, you don't just use strings.

It's the only sane way to program, currently. Modern languages are so poorly designed that they hinder you more than they help when you are trying to actually program at a high level if you care about what the results are at the low level, which I do.

- Casey


Hey! Didn't get an answer so I'll try asking again. Do you have in mind to do any sort of metaprogramming for handmade hero?

If not could you take a moment to briefly describe what it looks like to use whatever metaprogramming tool you've used? I haven't had the opportunity to be exposed to any sort of C metaprogramming -- just templates. Maybe if I had an idea of what using the tool looks like I could go and figure out how to implement such an idea.
I think perhaps a more interesting question for me would be: What are the problems that you (Casey) are solving with Meta Programming?

I would love to see even a 30 min demo of what your setup is and how you distinguish between meta code and regular code.

Edited by Ian Hern on
You know what would be more in the spirit of Handmade Hero? If someone here (other than Casey) just started trying it and seeing what approaches work, which don't, and what problems you can solve with C metaprogramming. There are a lot of smart people here, surely Casey doesn't need to give us training wheels for everything. I am already in the middle of my own project inspired by Handmade Hero, otherwise I would probably be all over this!
I *might* come up with something like this later next year. I was actually planning to do that eventually. I've always wanted to write my own language, but I've resolved to start with a some C extensions to try my hand at the stuff.

(I actually did something similar for Java for my master's thesis, although it is awfully impractical. Hoping to apply the lessons I learned there.)
Oh My God!!!

Too much stuff to learn!
handmade hero delivered a huge amount of information in different topics.
But at the end it can't cover everything which is unfortunate.

we need more handmade heros