5 ms·
Advanced metaprogramming in C
- rumcajz 11y agoThe "linked list on the stack" mechanism can be used even outside of metaprogramming context. Imagine you are traversing a binary tree and while doing so, you want to keep some data associated with every ancestor node of the one being processed at the moment: void foo(node *n, mylistitem *list) { mylistitem item; item.next = list; ... if(n->left) foo(n->left, &item); if(n->rigth) foo(n->right, &item); }
- CyberDildonics 11y agoA common optimization in hierarchical trees is to have each node actually hold multiple levels. This can be especially efficient if the node data can fit as a small multiple of the size of a cache line (64 bytes on modern Intel processors).
- adrusi 11y agoDoesn't libcurl encourage allocating linked lists on the stack for passing options to functions? IIRC a lot of functions take too many options to be practically specified as arguments so they have a datatype something like struct opt { enum option_specifier id; void *val; struct opt *next; }; And the functions that accept these option lists don't take ownership of them, so they're safe to allocated on the stack.
- rumcajz 11y agoYes. That sound like the same thing.
- vinkelhake 11y agoI was surprised to see that the linked "real world" implementation actually defines a bunch of macros with very generic names like "in", "out" and "end". The "standard" way of doing these things would be to name them MILL_IN etc. Not as pretty, but less likely to cause problems down the road.
- comex 11y agoTypo: in the user code example, I think the second should be in rather than out. This is pretty cute - looks useful in practice. I think you can slightly enhance the probability of the compiler making the result efficient by using a switch statement, like: goto setup1; got_value: switch (value) { setup1: ...setup 1...; goto setup2; case 1: ...; break; } etc. In C++, you could do something fairly equivalent with lambdas, without having to involve the "evil" preprocessor.
- rumcajz 11y agoUh, fixed. Your solution looks a lot like Duff's device :)
- theseoafs 11y agoOr you could just use functions to do the same thing. I assure you you did not invent building linked lists on the stack. By the way, you should be wrapping your giant macros (when they are necessary and useful; they aren't here) in do {} while (0) blocks.
- rumcajz 11y agoNow you made me curios. How would you go about doing it with functions? Keep in mind that the goal is to interleave conditions and the code in switch-like way.
- theseoafs 11y agoThe goal is to implement the desired functionality in a comprehensible way. Given that, the best option would be to use an array, and to initialize it with the easy array intialization syntax that C provides: struct select_condition conds[] = { { channel_1, SELECT_OUT, NULL, 42 }, { channel_2, SELECT_IN, &i, 0 } }; No need to overcomplicate it or stuff a bunch of functionality into macros in order to make C look like some other language.
- rumcajz 11y agoThe goal is not to look like golang but to maintain locality: Implementation of one thing should be at one place, not at two different places.
- kayamon 11y agoSeems like the 'classic' C way to go about it would be to use scanf/printf-style format strings: int mode = select("<%i | >%i", channel1, 42, channel2, &i); switch(mode) { case 0: foo(); break; case 1: bar(i); break; }
- deleted 11y ago[deleted]
- fizixer 11y agoIMO, any discussion about C metaprogramming should mention m4 [0], [1], a superior alternative to preprocessor macro system. [0] http://www.gnu.org/software/m4/m4.html http://www.gnu.org/software/m4/m4.html [1] http://www.ibm.com/developerworks/library/l-metaprog1/ http://www.ibm.com/developerworks/library/l-metaprog1/
- comex 11y agoIt's easy to be better than cpp, but without the ability to inspect the AST rather than raw text, you can't do the really cool things that macros in languages from Scheme to Rust can. (I've also heard bad things about m4's usability, though I haven't learned to use it myself.) If anyone wants to try to retrofit such functionality into C programs and is willing to add an extra command to the build (as m4 would require), I'd suggest implementing the macros in Python and using pycparser - or using some language's clang bindings or other compiler interfaces, but that has the disadvantage of more dependencies.
- fizixer 11y agoYou raise a very interesting point. In fact, python and C being my favorite two languages, and I'm trying to do some metaprogramming in some python-C hybrid way, I'd be very interested in looking into this. The other thing I'm spending a lot of time on these days is 'TeX' (specifically LaTeX but I've explored the internals of the system a bit). As TeX is also a macro system, which probably could be made to work as a general-purpose macro system, I'm interested in how cpp, m4, TeX, and lisp/scheme macros compare and contrast.
- mzs 11y agoI've had some success doing the meta programming in python, which generates .cpp (since the preprocessor does some expansion, it's not C++) files that I include from and .h file which I include in C code. It's harder to go the other way. It lets you basically modify only the python source and then have the same names for structs (classes in python) in both languages. But then I realized it was all pretty complicated. So I started using ctypes instead. That way I only wrote it once in a header file. The only real limitation when using cpython was that I could only include a maximum of one other struct in each struct, so sometimes the C header files were a bit strangely written.
- Animats 11y agoGroan. If you want that sort of thing, go to C++. C macros are deliberately restricted to prevent them from being used too much.