Live data from Hacker News

The beauty and simplicity of the good old C-style void* in C++

giodicanio.com

151–160 of 182 posts

Re: The beauty and simplicity of the good old C-style void* in C++

#151

Earlier quoted context omitted.

Yeah but also, quick question: struct S { char c; int i; }; struct S a = {0}; struct S b = {0}; memcmp(&a, &b, sizeof(a)) == ... If you answered 0, you'd be wrong, the answer is undefined, thanks to padding, initialization and alignment rules. Padding bytes are undefined, and not guaranteed to be initialized to zero even if the variable is declared static (where the members would be zeroed). This is why the compiler…

Padding bytes are initialized to zero if you zero initialize the aggregate. It is hard to keep those bytes as zero but at initialization this much is guaranteed.

I looked into it some more and it's actually worse.

For static or thread storage, in C11 and later, ={0} will guarantee padding is zeroed. For automatic storage, per C11 6.7.9, only subobjects are required to be zeroed. Padding is not. [1]

In C23 initializing with ={} will give you zeroed padding, initializing with ={0} will not.

[1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf

Re: The beauty and simplicity of the good old C-style void* in C++

#152

Earlier quoted context omitted.

I don't have a strong opinion what is better in this case, but my view is: > document and express intent clearly Arguably, the void* does that as well? > Any seasoned C++ developer seeing this knows what this reinterpret_cast means. Same for void*? > it's a bit more text to read If you have to call it many times, this adds up. > Some might also say it complexifies and uglifies the code I think the point is that it ad…

> Arguably, the void* does that as well? How do you figure? The type is a pointer to quite literally anything, including nothing (ie a pointer that cannot be dereferenced). If you're working with bytes, indicate this with the type.

> The type is a pointer to quite literally anything

No, it can only be a pointer to an object. It can't be a pointer to a function, for example.

Re: The beauty and simplicity of the good old C-style void* in C++

#153
post #60

Earlier quoted context omitted.

> a "simple" and "beautiful" function that was mangled into incomprehensibility over the years, and where if a more expressive type signature had been written from the start, it would have restricted the damage caused over time. ...Can you give a concrete example? I've been programming literally since the 80s and that doesn't ring true at all for me.

I can't, as my employer owns the code, not me, but there are several examples in one of the Ruby codebases I unfortunately maintain where I can see this degeneration happen via the git history. A small 8 line method with just two parameters slowly grows in complexity over time, until one day one of the original parameters supports two different shapes, and later on it's not that easy to understand which shape it shou…

You’re really citing a mess in a Ruby code base caused by lack of typing as evidence for why void * is problematic in C/C++?

These are so wildly different cases that the comparison isn’t meaningful. This is like saying you should wear a helmet while playing tennis because sometimes helmets save bicyclists lives.

Re: The beauty and simplicity of the good old C-style void* in C++

#154

Earlier quoted context omitted.

Can you point to it? That doesn't sound like "the language forced all this extra baggage on it due to 'safety'" so much as the developers kept adding functions to the function without rethinking if and how they should.

My point was not about the safety of the code, it was about the expressiveness, which is also what the comment I replied to was about. If the parameter has an explicit type (instead of no type, as is normal in Ruby, or `void*`, which is the C equivalent), it forces the developer to consider the design of the function, instead taking the path of least resistance because they're inexperienced/incompetent/a large langua…

> instead of no type, as is normal in Ruby, or `void`, which is the C equivalent*

“void *” is not the equivalent of “no type” from Ruby. “void *” says “I operate on raw memory”. It says exactly the same thing as “byte *”.

For sure you should generally not write a function that accepts a “void *” and then internally casts it to some concrete pointer type and operates on that type, but the problem there is the internal behavior, not the choice of byte vs void pointer.

Re: The beauty and simplicity of the good old C-style void* in C++

#155
post #56

Earlier quoted context omitted.

I don't have a strong opinion what is better in this case, but my view is: > document and express intent clearly Arguably, the void* does that as well? > Any seasoned C++ developer seeing this knows what this reinterpret_cast means. Same for void*? > it's a bit more text to read If you have to call it many times, this adds up. > Some might also say it complexifies and uglifies the code I think the point is that it ad…

> Arguably, the void* does that as well? Sort of (I mean: seeing void* and a size probably means 'arbitrary sequence of bytes' or something like that, but well it's void* so it can be like anything whereas with std::span you get more of a hint what's going on just based on the type), but not at the callsite which is what the author is referring to when it's about reinterpret_cast. > I think the point is that it adds…

> whereas with std::span you get more of a hint what's going on just based on the type

You don’t if it’s a span of bytes (or equivalent).

Encoding the length in a span is a meaningful thing. But the fact that it holds a random memory pointer labeled “byte” instead of “void” doesn’t change anything.

Re: The beauty and simplicity of the good old C-style void* in C++

#156

Earlier quoted context omitted.

I don't have a strong opinion what is better in this case, but my view is: > document and express intent clearly Arguably, the void* does that as well? > Any seasoned C++ developer seeing this knows what this reinterpret_cast means. Same for void*? > it's a bit more text to read If you have to call it many times, this adds up. > Some might also say it complexifies and uglifies the code I think the point is that it ad…

> Arguably, the void* does that as well? How do you figure? The type is a pointer to quite literally anything, including nothing (ie a pointer that cannot be dereferenced). If you're working with bytes, indicate this with the type.

All pointers in C/C++ can point to “nothing”. Swapping “void *” for “byte *” is basically an aesthetic choice.

Re: The beauty and simplicity of the good old C-style void* in C++

#157
post #108

Earlier quoted context omitted.

> Easy, even one of the author's could not change WG14 mind towards security. Your comment conveys a hefty dose of ignorance on the topic. I recommend you read the proposal's arguments, including how it required breaking the ABI.

Are you asserting that WG14 never had the necessary skills among all the members to help improve this proposal, or dare to bring another one during the last 40 years?

> Are you asserting that (...)

No, I called out your opinionated ignorance on the topic.

> WG14 never had the necessary skills among all the members to help improve this proposal (...)

Frankly I don't think you even understand what you're arguing. I mean, to start off, if an idea is feasible then do you think it needs a full blown committee joining forces to magically fix all the problems?

> (...) or dare to bring another one during the last 40 years?

Again, you are showing a hefty dose of ignorance in the topic. Do you even understand that anyone can put together a proposal? That's how the process works. If you feel so strongly about it, where is yours? What have you been doing for the past 40 years?

Re: The beauty and simplicity of the good old C-style void* in C++

#158
post #60

Earlier quoted context omitted.

It seems unlikely that this is the case, as the author appears to be experienced, but the post reads like the author has never had to maintain a "simple" and "beautiful" function that was mangled into incomprehensibility over the years, and where if a more expressive type signature had been written from the start, it would have restricted the damage caused over time.

> a "simple" and "beautiful" function that was mangled into incomprehensibility over the years, and where if a more expressive type signature had been written from the start, it would have restricted the damage caused over time. ...Can you give a concrete example? I've been programming literally since the 80s and that doesn't ring true at all for me.

> ...Can you give a concrete example? I've been programming literally since the 80s and that doesn't ring true at all for me.

Even this week I stumbled upon legacy code that started off with a clean function, void DoSomething(Foo). Then a few years passed and someone started using Foo to handle two scenarios, let's call them Left and Right. They could have simply introduce two new types, FooLeft and FooRight. But no. Instead they kept Foo after adding a few extra optional fields, and extended DoSomething(Foo) as

    DoSomething(Foo foo, bool isLeft, bool isRight)
This took place during the mid 2010s.

Where have you been during all this time?

Re: The beauty and simplicity of the good old C-style void* in C++

#159
post #153

Earlier quoted context omitted.

I can't, as my employer owns the code, not me, but there are several examples in one of the Ruby codebases I unfortunately maintain where I can see this degeneration happen via the git history. A small 8 line method with just two parameters slowly grows in complexity over time, until one day one of the original parameters supports two different shapes, and later on it's not that easy to understand which shape it shou…

You’re really citing a mess in a Ruby code base caused by lack of typing as evidence for why void * is problematic in C/C++? These are so wildly different cases that the comparison isn’t meaningful. This is like saying you should wear a helmet while playing tennis because sometimes helmets save bicyclists lives.

> You’re really citing a mess in a Ruby code base caused by lack of typing as evidence for why void * is problematic in C/C++?

If you read GP's post you'll understand it exemplifies exactly the issue that the likes of (void *) present in C.

I mean, read the message, particularly this:

> later on it's not that easy to understand which shape it should have in the specific conditional branch you're trying to fix

That is exactly the purpose of void *. By design. It's a pointer to an unspecified type. The unspecified type is exactly why this thing is used.

Re: The beauty and simplicity of the good old C-style void* in C++

#160

Earlier quoted context omitted.

Untrue. Lots of effort is spent optimizing compilation time at big FAANG companies. And there a lot of established techniques for creating “compiler firewalls” and explicitly instantiating templates once.

But these compilation times optimizations don't significantly undermine the other goals. Given that we're talking about std::span , a pretty small template all things considered, I think practical evidence (e.g. actual cases) of impact is needed.

The problem is not the size of the span template, it’s putting whatever logic into a header file instead of a sealed compilation unit.

In a void* function prototype, whatever network code or gnarly dependency is all shielded behind a compilation unit. If you make it a template function the compiler will have to (re)process a lot of code. You could make the interface templatized in a header file and have the actual implementation use void * or char * pointer. That would recover good compiler performance.

I don’t think span provides much if any safety for the implementer of the library function. I’m also not convinced it’s more ergonomic for the caller.

Post reply on HN