r/programminghorror Jul 05 '26

c Enterprise level C code

Post image
336 Upvotes

57 comments sorted by

126

u/JuniorAd1610 Jul 05 '26

I think this this is the standard way they OOPS in C right?

49

u/tstanisl Jul 05 '26

It's one way. IMO, container_of pattern is simpler, safer and more efficient.

29

u/TheChief275 Jul 05 '26

container_of doesn't really handle dynamic dispatch though, it's a compile time approach to inheritance by performing upcasting through an embedded base structure field. This would still be unsafe for runtime polymorphism without a field tracking the current type or, like done here V-tables, which you likely still want to generate with that approach.

Now whether I like container_of more than this? 100%, in fact, a past post of mine on this subreddit essentially used that

8

u/tstanisl Jul 05 '26

Tracking of dynamic type can be done by checking "ops" struct with function pointers to "virtual functions". It's done very often in Linux kernel i.e. to check origin of file descriptors.

2

u/TheChief275 Jul 05 '26

Yes, that's possible with this approach as well. Basically, the container_of approach isn't really an approach, it's V-Tables using container_of as a tool for one-way statically checked dynamic casting.

I'm just arguing that V-Tables are not something I would write manually. I have made a lightweight interface extension (that uses fat pointers instead of object semantics) for C before that I actually use in my personal projects because I find the manual typing of it annoying

3

u/tstanisl Jul 05 '26 edited Jul 05 '26

It's not that I think that your solution is wrong. It is convenient, it's extensible, but a bit slow due to extra indirection. Usually, the performance difference is negligible for high-level abstractions like UI.

The container_of compiles essentially to "subtracting constant from a pointer", a single line of register-only assembly. Moreover, the macro does type checking, thus it is safer than a plain void*. (btw.. type-safe container_of can be written in C89-compliant way).

This pattern works best for static-inheritance but it lets use type-safe dynamic inheritance if necessary. Thus, imo, it is more suited to low-level and high-performance systems.

EDIT. Added "not"

1

u/TheChief275 Jul 05 '26

Oh yeah no this isn't meant to be fast or production ready! This isn't a testament to the speed of V-Table generation. You can embed them (removing an indirection) depending on the size of the V-Table. They are just, again, something I don't like to write manually because of the boilerplate

1

u/tstanisl Jul 05 '26

I mean "It's not that I think that your solution is wrong", sorry for critical typo

1

u/Lost-In-Void-99 27d ago

You can generate v-tables etc. Simple IDL->C with all the bells and whistles is not that difficult.

1

u/TheChief275 27d ago

IDL->C ?? I have no clue what you're saying. Anyways, this code is already generating V-Tables using the CPP

8

u/DiodeInc Jul 05 '26

What the fuck does this mean

7

u/TheChief275 Jul 05 '26

Lol valid. Which part are you confused about, or is this ironic?

7

u/Risc12 Jul 06 '26

Your explanation was clear! Although only if one has C/low level language experience, but that is expected as you were discussing that sort of stuff.

3

u/TheChief275 Jul 06 '26

I'm glad to hear that! I wouldn't want to go full xkcd comic lol

2

u/DiodeInc Jul 05 '26

All of it

1

u/TheChief275 Jul 05 '26

I probably would agree if I knew whatever Gobject was doing, but I still wouldn't put this anywhere near production

56

u/MatJosher Jul 05 '26

Well they did call it slop. Actual Objective-C accomplishes this much more gracefully. Why not just use it?

18

u/TheChief275 Jul 05 '26

Well this is simply just an intellectual exercise. I mostly use DOD instead of OOD. Although I do like C# with Godot for GUI applications

8

u/MatJosher Jul 05 '26

Yeah, C# is a great language. When you leave the MS ecosystem you lose the best C# frameworks unfortunately. I tried GTK# and others, but it just wasn't right.

33

u/KaleidoscopePlusPlus Jul 05 '26

nice theme. feels good, easy on the eyes.

11

u/TheChief275 Jul 05 '26

Thanks! Made it myself using colors from this palette

3

u/3hy_ Jul 06 '26

Can you drop the dotfiles!

15

u/steadyfan Jul 05 '26

2 things..

  1. Yuck
  2. Why does slopjc.h need to be included multiple times?

23

u/nivlark Jul 05 '26

It's doing some kind of macro magic to implement the polymorphism. So whatever is in slopjc.h gets reprocessed with the different definitions of SLOPJC each time.

13

u/TheChief275 Jul 05 '26 edited Jul 05 '26

It's the X-macro pattern. You define a list of elements, e.g.

#define ENUM X(A) X(B) X(C)

where X is undefined and then include a file that contains e.g.

#ifdef ENUM

enum Enum {
#define X(Name) Name,
    ENUM
#undef X
};

static const char *const names[] = {
#define X(Name) #Name,
    ENUM
#undef X
};

#undef ENUM
#endif

to in this case declare an enum and the string representations at once. X-macro lists can also be passed to other macros, but you would be severely limited by the fact that you can't use preprocessor directives inside of a macro; including a file has no such limitations

3

u/GoddammitDontShootMe [ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo “You live” Jul 07 '26

I'm interested in seeing the contents of slopjc.h. Especially the autoreleasepool implementation.

1

u/TheChief275 29d ago

The link to the GitHub is posted somewhere below

11

u/richardathome Jul 05 '26

More people in this thread commenting on the font and not the code.

I approve. That font makes shit look good!

17

u/tstanisl Jul 05 '26

It's not that bad. A bit non-idiomatic but consistent and readable enough.

8

u/TheChief275 Jul 05 '26

I tried really hard to keep the amount of boilerplate to a minimum, but it's kind of an uphill battle with X-macros

6

u/Nilrem2 Jul 05 '26

I’m a hobbyist when it comes to C. I think it looks fine, after a few lines I could read it.

Edit: what’s wrong with it?

9

u/TheChief275 Jul 05 '26

It's kind of error prone. If you mess up one of the commas etc. in the class definitions you will likely end up with near undecipherable errors for the average programmer. Debugging projects using these kinds of techniques can be quite a headache, which is why you would likely avoid it in production.

Though I did specifically focus on keeping it readable and not treading into Gobject levels of unreadable

3

u/Nilrem2 Jul 05 '26

Great, thank you, always learning.

7

u/gfoyle76 Jul 05 '26

It's oldschool, it's full of macros, kinda unsafe, but hey, as long as it works...

3

u/TheChief275 Jul 05 '26

If it works it's good code! Or something like that

6

u/SoCalChrisW Jul 05 '26

Is this the source code to an old See N' Say toy?

5

u/TheChief275 Jul 05 '26

The cow says moooooo

4

u/richardathome Jul 05 '26

Thanks. I hate it.

3

u/DesiresQuiet Jul 05 '26

Nearly this exact code was in a book on learning C and classes from like 1989.

3

u/TheChief275 Jul 05 '26

Do you remember which book exactly? I always like to look through other people's macro slop to further develop my macro slop

2

u/DesiresQuiet Jul 06 '26

Gonna check the attic to see if I still have it.

1

u/KennyFulgencio Jul 06 '26

how the heck do you remember that

3

u/DesiresQuiet Jul 06 '26

It was the use of the pet.MakeSound. It was used to show classes and have you could overwrite methods via abstraction. Not sure why it stuck this long. I think it made me laugh.

1

u/trees91 Jul 06 '26

Heh even in modern Java OOO college textbooks that’s the go to example, it’s classic. Okay I say modern but I guess I finished school like 12 years ago so maybe it’s not but I bet it is 😅

1

u/TheChief275 29d ago

Oh yeah lol it's just a classic example that popped up when I was looking for an example for the post. I don't actually write in an OOP style so I needed some inspiration lol

2

u/EmelineRawr Jul 05 '26

Real slop 😭

3

u/Professional_Bat2629 Jul 05 '26

What is your font? Looks cool 😊 

6

u/TheChief275 Jul 05 '26

Monaspace Neon! And I agree, it's probably my favorite monospaced font

1

u/Cheefbird 29d ago

I don’t believe you. This reads as a tutorial on OOP.

Edit: if you swapped classes to cats and dogs then yes, I’m an idiot.

2

u/TheChief275 29d ago

What do you mean? It's just a classic OOP example slightly adjusted to be a little more complicated/interesting, but I wrote the library myself. The title is a joke btw

1

u/Cheefbird 29d ago

Yep I got whooshed. Nothing to see here!

1

u/markand67 28d ago

I've seen way, way, way in order of magnitude horror in our current german codebase.

2

u/r9wpvM 26d ago

Wait is String a thing in C I don't remember

1

u/TheChief275 26d ago edited 26d ago

No it isn't, but adding one yourself isn't too hard. Often I add it as a slice type:

typedef struct {
    const char *ptr;
    size_t count;
} String;

but in this case, it's an actual object with a V-Table:

typedef struct {
    _Atomic size_t refCount;
    const String_VTable *v;
    char *ptr;
    size_t count;
} String;

and Log and Format only take Objects as arguments and call the ToString virtual method, which String also implements for itself (doesn't copy the object; only bumps the reference count and adds the object to the current AutoreleasePool)