Live data from Hacker News

Type-safe generic data structures in C

iafisher.com

51–57 of 57 posts

Re: Type-safe generic data structures in C

#51
post #32

Earlier quoted context omitted.

> assert(p); > if (p) { Do you want me to have an embolism?

Haha. I was amused/bewildered by: void *p = realloc(...) // ... cast every other occurrence of p to (int *) ... The concept may be interesting, but this particular implementation is needlessly horrible.

That's actually correct C pointer arithmetic.

When you increment a pointer, it moves ahead by the sizeof the underlying concrete type. If the pointer is to void, there is no underlying type and in fact void pointer arithmetic is disallowed by the standard. GCC lets you do it with an extention: https://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Pointer-Arith.h...

So in this case, since the headers for the arrays are made up of two int's it's the right thing to do to move around by sizeof(int) memory address units. You do this with a cast before the arithmetic.

Re: Type-safe generic data structures in C

#52
post #27
post #9

Author here. I wish I had made it clearer that the intent of the post was "this is an interesting and surprising thing you can achieve in C" and not "this is a good idea for a real software project" or "this is a reason to use C instead of C++/Rust/Go".

Macros of this sort are indeed used to define stacks, queues, deques, and other generic data structures in the NetBSD (and presumably other BSDs) source code. So the pattern is used in real software projects.

Also OpenSSL

Re: Type-safe generic data structures in C

#53
post #9

Author here. I wish I had made it clearer that the intent of the post was "this is an interesting and surprising thing you can achieve in C" and not "this is a good idea for a real software project" or "this is a reason to use C instead of C++/Rust/Go".

This is in fact a pretty common pattern in production code.

Here's an entire suite of type safe generic data structures in C: https://github.com/attractivechaos/klib

Re: Type-safe generic data structures in C

#54
post #32

A much more simple alternative way of doing this is to use stretchy buffers. Here's an example of a dynamic array in C in about 20 lines: http://nothings.org/stb/stretchy_buffer.txt And here's a friendly explanation of how this technique works: https://ourmachinery.com/post/minimalist-container-library-i...

> assert(p); > if (p) { Do you want me to have an embolism?

to be fair, if assert is removed in release code, you still have some protection with the `if`

Re: Type-safe generic data structures in C

#55
post #51

Earlier quoted context omitted.

Haha. I was amused/bewildered by: void *p = realloc(...) // ... cast every other occurrence of p to (int *) ... The concept may be interesting, but this particular implementation is needlessly horrible.

That's actually correct C pointer arithmetic. When you increment a pointer, it moves ahead by the sizeof the underlying concrete type. If the pointer is to void, there is no underlying type and in fact void pointer arithmetic is disallowed by the standard. GCC lets you do it with an extention: https://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Pointer-Arith.h... So in this case, since the headers for the arrays are made up…

My point was, why not declare the pointer as int * directly since that the only type it's used as?

Re: Type-safe generic data structures in C

#56
post #15

Earlier quoted context omitted.

I agree that you shouldn't be doing this stuff in production if you don't know the ends and outs of doing this idiomatically. For instance, the lack of parenthesis ala #define SQ(x) ((x)*(x)) set off my C spidey senses. I use them even for constants in pound defines just to be consistent. That being said, there are benefits, like the type safety listed being one of them. No weird cast to void* and go to town on raw m…

You mean: #define SQ(x) ((x)*(x))

There's another pitfall: it evaluates a parameter twice. Imagine calling SQ(func_with_side_effects()).

If you can assume a compiler with statement expressions and typeof (gcc, clang, probably icc in this case):

#define SQ(x) ({ typeof(x) x_ = (x); x_ * x_ })

If not (MSVC++) then best of luck.

Anyway I 100% agree people way, way overuse macros. Very often a static inline function is a better trade-off.

Re: Type-safe generic data structures in C

#57
post #49

Earlier quoted context omitted.

99% of ARM usage is done in little endian. all android & ios phones, all embedded boards that ship with linux, etc. are always configured in little endian.

Okay, assuming you're right, how much overhead is it to consider endianness? I've never had issues with it, unless I'm implementing something fully from scratch, and that's rare in a production environment.

People that deign network protocols love love big endian.

Which means on the software side you then have to swap everything from big endian to little endian. And you need to do that at the first opportunity so their big endian crap doesn't get loose in the rest of the code.

Post reply on HN