7 ms·
Advanced Metaprogramming in C: A select statement
- mckirk 4y agoOn the one hand, I personally enjoy exercises like this, and the end result is quite pleasing to look at. On the other hand, the whole idea is kind of funny to me. In my experience, a proclivity to programming serious low-level code in C very much comes with an intense defensive reaction to things like "metaprogramming using the C precompiler". At least I still vividly the remember my co-workers' reaction to the C code I wrote as an intern, when I tried to be clever.
- comma_at 4y agolibmill's goal was to be as close to Go as possible. If you look at it in that light, it's an accomplishment. Then came libdill, which created the whole "structured concurrency" movement and brought new concepts to light that are now being replicated in python, kotlin, java...
- jesse__ 4y ago> programming serious low-level code in C I mean.. a lot of code that's written in C isn't particularly "low level" in the sense that it's optimizing for runtime or memory in any kind of outrageous way. A lot of C is very normal/straight forward code which can benefit greatly from metaprogramming due to the lack of language-level niceties. > I still vividly the remember my co-workers' reaction to the C code I wrote as an intern, when I tried to be clever. That's understandable. I'm highly skeptical of clever code anyone writes, including myself. I guess what I'm trying to say here is that metaprogramming and being clever aren't mutually intertwined ideas.
- rrdharan 4y agohttp://libmill.org/ http://libmill.org/ “is in an active auction”. https://www.sav.com/auctions/details/1159199/libmill.org https://www.sav.com/auctions/details/1159199/libmill.org Insert some joke about the dangers of overly abusing the C precompiler…
- pcr910303 4y agoAFAIK It’s http://libdill.org http://libdill.org now :)
- s-video 4y agolibmill and libdill are similar but different projects by the same author. I think he just let the libmill domain expire. What's funny is the site is a GitHub Pages site, so it's still there on the libmill repository, and could be accessed at https://sustrik.github.io/libmill https://sustrik.github.io/libmill but it's configured to redirect to that expired libmill domain so it's inaccessible.
- pid_0 4y ago
- jxy 4y agoUsing initializer list would be much more readable without the atrocious macros.
- jesse__ 4y agoCare to elaborate, or better yet link to a gist? Initializer lists aren't a thing in C, so I assume you're referring to array initialization : https://en.cppreference.com/w/c/language/array_initialization https://en.cppreference.com/w/c/language/array_initializatio... And with that said, I fail to see how using an initializer would have any effect on the end result.. unless of course you only read the first 150 words. Then your comment, while unnecessary, would make sense.
- david2ndaccount 4y agoInitializer-lists are most definitely a thing in C and are part of the grammar. Check 6.7.9 of your C standard struct Foo { int x, y; }; struct Foo foo = {1, 2}; // ^ this is an initializer list. They also include designators, like: struct Foo foo = {.x=1, .y=2}; The straw man struct initialization at the beginning of the article would be greatly improved with such a construct. Once you are no longer messing with macros, the rest of the article becomes a step too far. I assume the article was for c89, as c89 did not allow non-constant initializers. Any modern C compiler should compile c99 or newer code though.
- jesse__ 4y agoAhh, now I see what you're saying; that does seem true. Sorry for the snarky comment.
- Gibbon1 4y agoYour comment made me look at the article. I saw this line > Can we somehow not require the user to specify the size of the pollset in advance? The answer for gnu99 is yes. // will barf if fed a pointer #define sizeof_array(arr) \ (sizeof(arr) / sizeof((arr)[0]) \ + sizeof(typeof(int[1 - 2 * \ !!__builtin_types_compatible_p(typeof(arr), \ typeof(&arr[0]))])) * 0) typedef struct { int x, y; } Foo; Foo foo[] = { { .x = 10, .y = 20}, { .x = 11, .y = 23} }; foo_cnt = sizeof_array(foo); // foo_cnt == 2 One of the reasons why I think the C standards committee needs to be fired is because sizeof_array should have been made part of the language 20 years ago.
- WalterBright 4y agoIf you're using macros for metaprogramming in C, you've outgrown the language and are ready for a more powerful C replacement.
- Spivak 4y agoUnless you need it to be in C because you’re targeting platforms only supported by a C compiler or because you’re writing a library and want different languages to have FFI.
- WalterBright 4y agoWith D you can interface seamlessly to C, in both directions. D works fine at presenting a C interface any C code can use.
- LanternLight83 4y agoI've never thought about it that way before, and suppose that it applies to any language with a two-way FFI (including more diverse languages like, well, just Guile Scheme off the top of my head, but insure there are more-- I'm sure someone could really benefit from a list of languages that can essentially target C like this)
- tpoacher 4y agoyou mean, like, assembly?
- tpoacher 4y ago"A witty quote proves nothing." ~ Voltaire
- quelsolaar 4y agoI have thought a lot about meta programming and the best way to do it (I participate in the ISO C wg14) and I dislike macros, templets and every other attempt I have seen. The best solution I have found, disregarding of language, is to use the same language to write a program that generates the code you need. Then you can compile, and debug them separately using the same workflow, and each program can be clear and simple to read. Its not sexy or clever, but it works and anyone can understand what is going on. Almost always that turns out to be the most important thing.
- jesse__ 4y agoI definitely agree. I'm actually in the middle of writing a C metaprogramming runtime (effectively a parser that spits out an AST) which is useful for writing such programs. Also, unrelated, but I miss watching your streams on Twitch, assuming you're the same quelsolaar :)
- saghm 4y ago> The best solution I have found, disregarding of language, is to use the same language to write a program that generates the code you need. Sounds like a pitch for lisp; I haven't really used any lisp variant much, but I always hear about people saying they basically write a program to generate their program rather than actually just solving the problem directly.
- LanternLight83 4y agoAbsolutely; Complex macros are frequently written by breaking them up into smaller "actual" functions. The body of the macro just receives it's unevaluated arguments and calls those functions on them, because the only thing that's special about it is when it runs, that it's arguments are initially unevaluated, and that it's output is interpreted (possibly by a compiler) as code. Within the context of the macro's body, it's lisp like any other.
- kaba0 4y agoOr zig’s compile time functions.
- jstimpfle 4y agoMetaprogramming should be limited, and metaprogramming in C is quite brittle and almost nobody really understand the execution model of he preprocessor. But, dismissing the preprocessor outright is too quick a conclusion. There are some clever and very practical uses of the preprocessor. - portability - generate strings from identifiers - Insert file and line of the call location (or other context) automatically when calling a function. - X-macros - Scopes with exit statement given at beginning, hacked using "for" statement and a condition that evaluates to true only the first time. A little bit brittle when the exit statement must not be skipped (goto, return). I'm sure there are more, but I'm too tired to think harder... Here is an example of the last category: #define TIMED_SECTION_(name, t) FOR_SCOPE(Timer t = start_timer(); print_passed_time(name, t)) #define TIMED_SECTION(name) TIMED_SECTION_(name, UNIQUE_NAME()) Not giving the FOR_SCOPE() and UNIQUE_NAME() macros here for brevity. They add another 3-5 reusable lines. Use like this: TIMED_SECTION("foo the bar") { /* Do stuff, time spent in this scope will be measured and printed on scope exit. */ } Other more advanced languages can do some of the same things, sometimes more robustly, or not at all (X-macros is probably hard to replace for languages that are not LISP). But it typically comes at a cost in complexity, hard to use type systems, complicated semantics with edge cases... And they only allow you to do what is already built into the language!
- kaba0 4y agoI don’t know, I would much rather prefer a sane metaprogramming system instead of this unhygienic mess of a hack.
- tpoacher 4y ago> However, such syntax is ugly and verbose. Is it just me who thinks this was by far the clearest, cleanest formulation? Everything following it seemed to sacrifice clarity for the sake of cleverness. Also I really dislike macros that try to disguise themselves as "not macros". Capitalise the crap out if it, make the fact that this is a macro stand out, man!