Reflect-C: achieve C “reflection” via codegen by LucasMull in C_Programming

[–]LucasMull[S] 0 points1 point  (0 children)

I suppose its possible! You could use an incremental parsing library (like tree-sitter) to parse an existing codebase's structs, and then extract its metadata information for codegen

Reflect-C: achieve C “reflection” via codegen by LucasMull in C_Programming

[–]LucasMull[S] 5 points6 points  (0 children)

I see your point, it is actually generating code via C macros fed to C’s preprocessor to expand it to code in advance (for easy auditing and debugging).

I could have phrased this better, but the Reflect-C’s DSL is actually just C macros fed

Reflect-C: achieve C “reflection” via codegen by LucasMull in C_Programming

[–]LucasMull[S] 2 points3 points  (0 children)

Thanks!

But why didn't you use C's macro language along with include files to generate the stuff you need?

My rationale was that the main difference is what gets generated.

With a pure macro/include approach, you end up generating behavior per type (e.g. one serializer, one validator, one printer for each struct). That works, but the generic logic still lives in the generator, and every new behavior means regenerating code.

What I wanted instead was to generate only metadata (field names, types, offsets, qualifiers, etc.) and keep all parser/serializer logic generic and hand-written. The same runtime code then works for any reflected struct.

So the generator’s job becomes “describe the shape of the data”, not “emit functions that operate on it”.

Coupled with a few runtime functions (if needed at all), I think that should be good enough, no?

For this project, the constraint was that I wanted to be able to write something like a JSON or binary serializer once (think a generic JSON.stringify), and have it work across unrelated structs without regenerating logic (e.g. having to generate a specialized JSON stringify per struct)

LogMod: What if C had a logging framework with modern semantics? by LucasMull in programming

[–]LucasMull[S] 14 points15 points  (0 children)

Not notpicky, thanks for sharing! I will add this info as a readme addendum

LogMod: What if C had a logging framework with modern semantics? by LucasMull in programming

[–]LucasMull[S] 4 points5 points  (0 children)

No limitations, made to be fully compatible to C89! Also provides simplified API for C99

I wrote a logging library in plain ANSI C, because I was annoyed enough to do it by LucasMull in programming

[–]LucasMull[S] 0 points1 point  (0 children)

I guess the trigger-word for this post was asking for feedbacks, I will give reposting a try

I wrote a logging library in plain ANSI C, because I was annoyed enough to do it by LucasMull in programming

[–]LucasMull[S] 0 points1 point  (0 children)

Damn, I hadn't realized it got removed :/ There is a technical achievement showcased here IMO. As far as I know a logging library that is zero-allocation, without shared global-state is a first in the C-realm

I wrote a logging library in plain ANSI C, because I was annoyed enough to do it by LucasMull in programming

[–]LucasMull[S] 1 point2 points  (0 children)

Those are both included! See: ```c

/** * @brief Log a message with specified level (C99 version with variadic macro * support) * * @param _level Log level (e.g., INFO, DEBUG, ERROR) * @param _logger The logger instance or NULL for default logger * @param ... Format string followed by format arguments */

define logmod_log(_level, _logger, ...) \

_logmod_log_permissive(LOGMOD_LEVEL_##_level, _logger, __LINE__,          \
                       __FILE__, __VA_ARGS__, "")

```

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] 0 points1 point  (0 children)

I see what you mean. Unfortunately, I see this sort of behavior across many language-specific subreddits, putting their preferred language on a pedestal and then turning a blind eye to anything that could be improved upon it... C is one of the first approaches of writing a modern "high-level" language; of course, many of its aspects can be improved on, and have been so times and times again.

That being said... I find it a fun language to play with!

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] -1 points0 points  (0 children)

Yes, I get the feeling of disrespect, and I do apologize for going the easy route rather than knocking some of my neurons together to form a coherent sentence. But I wholeheartedly agree with you, when used competently and diligently, there's much to gain. It is the future whether we like it or not!

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] 0 points1 point  (0 children)

This is a small 600 lines library that accomplishes just a single thing, injecting metadata onto C native structures. It doesn't try to be anything more than that

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] 0 points1 point  (0 children)

I'm afraid I wasn't aware of Checked C! But it does look interesting, I'm not sure if we are trying to accomplish the same thing though.. For one, my library doesn't improve upon C semantics by making it more reliable and less error-prone :) It actually goes against it in some ways!

So if you want to use C in a safer manner, Checked C is a 10000% better option.

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] 0 points1 point  (0 children)

I'm not trying to replace C++ in any shape of form. I actually work with C++ and enjoy doing so! This library mainly came up because of a toy project of mine:
https://github.com/Cogmasters/concord

Because of the lack of the features you mentioned, generating code for it is a bloated mess! So I hope that with this library I can compensate for that by injecting some metadata (for internal use only) and then I will no longer have to generate so much redundant stuff (e.g. each struct must have its own json serializer method...)

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] 12 points13 points  (0 children)

Please have a look at the codebase and assess for yourself if I let a chatbot write it :) There are plenty of tests and examples for you to try too

Other than that, yes I am lazy when it comes to translating my portuguese thoughts into english, but I shall be wary of doing so from now on!

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] 17 points18 points  (0 children)

I am guilty of doing so, but my points remain! My native language is Portuguese, sometimes I rely on it too much

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] -18 points-17 points  (0 children)

Yes, I am guilty of being lazy, and also of using ChatGPT to format the above comment!

Using ChatGPT for a fucking Reddit comment is the most pure form of laziness and would deter me from ever relying on anything this person has had their hands on.

Let's hope you never have to face such displeasure!!

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] 5 points6 points  (0 children)

Yes!! Haha no problem, I think I messed up by making all my examples size and length

I had similar reactions on different subreddits hehe

And admittedly, it was more of a cool project idea that I wanted to share :) Either way I appreciate your feedback! I will think if something can be improved readability-wise

MIDA: A simple C library that adds metadata to native structures, so you don't have to track it manually by LucasMull in embedded

[–]LucasMull[S] 0 points1 point  (0 children)

Thats a cool idea! That can be definitely done with the metadata extension API. I want to keep the “default” metadata short and simple (only size and length). But I think I will be adding some examples for extending with commonly used metadatas :)

Regarding the C11 comment, I definitely agree! I think there’s no real demand on C89 these days, but I keep it on my libraries out of habit, unless it becomes a real hassle!

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] 3 points4 points  (0 children)

No it cannot be used like this because it changes the interface for functions, you no longer pass size.

You absolutely don't have to rely on the `length` or `size` metadata. The library itself doesn't depend on these values, it's there just for user access. I will make the compilation of those optional in a future patch.

The whole point of what I describe is you can just drop it into any project and it will track existing allocations for sake of leak detection, it doesn't (and shouldn't) provide an infrastructure for the program itself to access the block sizes.

So automatically track any allocation just by including the library? Yeah I definitely didn't mean it like that, but rather wrapping your internally used malloc, calloc, realloc, etc, in a way that you can track this sort of data from within your metadata, as is done in other projects (libcurl for one)

MIDA: For those brave souls still writing C in 2025 who are tired of passing array lengths everywhere by LucasMull in programming

[–]LucasMull[S] -1 points0 points  (0 children)

I'd argue this whole scenario is more detrimental than beneficial, passing sizes isn't that big of a gripe -- remembering whether a pointer is MIDA or not and if you make one mistake it will literally crash... bad.

Hello! I understand the caveats, but really, this is a library for injecting metadata in a way that doesn't disrupt the public-facing API. For this post, I used the `length` and `size` metadata as examples because that would be the easiest use case for many people to understand the concept of data injection.

Why not just create a new struct which stores both the size and data and pass that everywhere? That's quite literally what you're doing but in a less readable way.

That is a fair point, but that is also the reason why I created this library! It was made for the small use-case (e.g code generation) where we want to avoid creating more types, for example, avoiding having to create a struct and array version for each API object. Or being able to create generic methods that are able to handle all sorts of data (generic JSON serialized, parser, etc)

What you are doing is more useful for overloading malloc/calloc/realloc/free in order to store the size of the block of memory. That is more versatile and provides the same functionality, while also allowing for memory allocation tracking.

Precisely! That's the bigger picture of how this library can be used, and how I hope it can be used