Live data from Hacker News

Struct Iteration Through Abuse of the C Preprocessor

natecraun.net

1–10 of 27 posts

Re: Struct Iteration Through Abuse of the C Preprocessor

#2
You can do some interesting things using __COUNTER__ to make code using this less ugly. And if you're willing to use a small amount of C++ templates, you can make it possible to resolve all the iteration/member info at compile time to eliminate runtime overhead.

I did both of these things for Grim Fandango for vertex/uniform buffers, so that the game could use buffers without caring about whether it was using OpenGL or console APIs - but it's not open source :-(

Even if you don't need something like this under normal circumstances, consider whether it could let you identify mistakes in debug builds, or avoid errors when writing your serialization code.

Re: Struct Iteration Through Abuse of the C Preprocessor

#5
post #4

Taking a step back: what you're trying to accomplish is code generation -- a program that generates code. From that perspective, why would you choose to write that program using the C preprocessor, when there are so many other nice languages around?

This is what I was going to suggest. C is even pretty easy to parse - you can just take the ready ANTLR grammar and use it to generate a parser in whatever language you want.

Of course, he might go even one step further and specify the structs in some other language, then generate C source files from them, which would also allow you to easily generate consumers for that data format in other languages and now you're reinventing Cap'n Proto.

Re: Struct Iteration Through Abuse of the C Preprocessor

#6
post #4

Taking a step back: what you're trying to accomplish is code generation -- a program that generates code. From that perspective, why would you choose to write that program using the C preprocessor, when there are so many other nice languages around?

In actual production use, I think it could be better to write a separate program that will generate the code for you instead of using the C preprocessor (or use a language with this kind of introspection built in). However, using this hack lets you depend only on the facilities of the language, and that can be useful in simplifying the build process. Plus it was fun to create, too!

Re: Struct Iteration Through Abuse of the C Preprocessor

#7
While it is true that compilers pad for alignment it is pretty easy to avoid that, at least in my experience.

So an easier approach, but more fragile, is just to define the struct, count up how big you think it should be and then do an

assert(sizeof(struct foo) == FOO_SIZE);

If that assert doesn't pop then you can just do

write(fd, &foo, FOO_SIZE);

I know that is a lot less elegant but it works and isn't doing the translation back and forth.

If you don't like that you might consider using Sun's RPC marshalling code that is (used to be?) part of Linux.

Re: Struct Iteration Through Abuse of the C Preprocessor

#8
post #6
post #4

Taking a step back: what you're trying to accomplish is code generation -- a program that generates code. From that perspective, why would you choose to write that program using the C preprocessor, when there are so many other nice languages around?

In actual production use, I think it could be better to write a separate program that will generate the code for you instead of using the C preprocessor (or use a language with this kind of introspection built in). However, using this hack lets you depend only on the facilities of the language, and that can be useful in simplifying the build process. Plus it was fun to create, too!

It can be a bit tricky if it isn't integrated with the build process.

Re: Struct Iteration Through Abuse of the C Preprocessor

#9
Wow, I just finished doing something similar. The use of x-macros is definitely a little cleaner / canonical than my approach, which instead "recurses" through a VA_MACRO. For an excellent guide on recursion in macros, see this article on how to abuse the C pre-processor: https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,....

In the end I end up defining structs like this: SERIALIZER_STRUCT( structname, int8_t, field1, int16_t, field2, ... );

Initializing them like this: structname instance = {.field1 = 1, .field2=2};

and serializing them like this: SERIALIZER_SERIALIZE( structname, &instance, bigbuff_ptr );

As for just using a packed structure, there are definitely caveats with some compilers (ie: compilers for embedded systems may not handle various edge-cases for misaligned access, particularly when dereferencing pointers to structs.)

Re: Struct Iteration Through Abuse of the C Preprocessor

#10

While it is true that compilers pad for alignment it is pretty easy to avoid that, at least in my experience. So an easier approach, but more fragile, is just to define the struct, count up how big you think it should be and then do an assert(sizeof(struct foo) == FOO_SIZE); If that assert doesn't pop then you can just do write(fd, &foo, FOO_SIZE); I know that is a lot less elegant but it works and isn't doing the tr…

Yeah, in poking around it looks like RPC is still a thing and it's solved this problem in an automated way.

http://docs.freebsd.org/44doc/psd/23.rpc/paper.pdf

http://docs.freebsd.org/44doc/psd/22.rpcgen/paper.pdf

Post reply on HN