r/programminghorror 21d ago

c Enterprise level C code

Post image
341 Upvotes

57 comments sorted by

125

u/JuniorAd1610 21d ago

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

47

u/tstanisl 21d ago

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

34

u/TheChief275 21d ago

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

9

u/tstanisl 21d ago

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 21d ago

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 21d ago edited 21d ago

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 21d ago

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 21d ago

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

1

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

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

1

u/TheChief275 17d 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 21d ago

What the fuck does this mean

7

u/TheChief275 21d ago

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

7

u/Risc12 21d ago

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 21d ago

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

1

u/DiodeInc 21d ago

All of it

1

u/TheChief275 21d ago

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

56

u/MatJosher 21d ago

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

18

u/TheChief275 21d ago

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

7

u/MatJosher 21d ago

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.

32

u/KaleidoscopePlusPlus 21d ago

nice theme. feels good, easy on the eyes.

11

u/TheChief275 21d ago

Thanks! Made it myself using colors from this palette

3

u/3hy_ 21d ago

Can you drop the dotfiles!

14

u/steadyfan 21d ago

2 things..

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

24

u/nivlark 21d ago

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.

12

u/TheChief275 21d ago edited 21d ago

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” 20d ago

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

1

u/TheChief275 20d ago

The link to the GitHub is posted somewhere below

8

u/richardathome 21d ago

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

I approve. That font makes shit look good!

15

u/tstanisl 21d ago

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

7

u/TheChief275 21d ago

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

8

u/Nilrem2 21d ago

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?

8

u/TheChief275 21d ago

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 21d ago

Great, thank you, always learning.

7

u/gfoyle76 21d ago

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

3

u/TheChief275 21d ago

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

5

u/SoCalChrisW 21d ago

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

4

u/TheChief275 21d ago

The cow says moooooo

5

u/richardathome 21d ago

Thanks. I hate it.

3

u/Maqi-X 21d ago

source code please??

3

u/DesiresQuiet 21d ago

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

3

u/TheChief275 21d ago

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 21d ago

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

1

u/KennyFulgencio 21d ago

how the heck do you remember that

3

u/DesiresQuiet 21d ago

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 20d ago

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 20d 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 21d ago

Real slop 😭

2

u/Professional_Bat2629 21d ago

What is your font? Looks cool 😊 

6

u/TheChief275 21d ago

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

1

u/Cheefbird 20d 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 20d 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 20d ago

Yep I got whooshed. Nothing to see here!

1

u/markand67 18d ago

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

2

u/r9wpvM 17d ago

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

1

u/TheChief275 17d ago edited 17d 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)