frontpage.
newsnewestaskshowjobs

Open Source @Github

fp.

Open in hackernews

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

https://giodicanio.com/2026/06/05/how-to-declare-a-c-plus-plus-function-that-takes-a-blob-of-memory/
16•movd128•2d ago

Comments

gignico•1h ago
> It seems that some people are really losing the taste for good readable code.

It seems that some people never had taste for good reliable code. Use `void ` and now any error whatsoever is a direct undefined behavior. Moreover `std::span` clearly says that you are not* taking ownership of the memory (even though the language does not check it of course), while `void *` does not.

I understand that people can have many things to say about C++, and I do as well, but `std::span` should have been there decades ago and is such a life saver in these situations. A truly zero-cost abstraction which effectively saves you from a lot of troubles.

spacechild1•48m ago
> but `std::span` should have been there decades ago

Absolutely! I now use it consistently in all new projects where I can afford to mandate C++20. I guess nobody bothered to make a proposal before...

pjmlp•8m ago
They did in C, from one of the language authors even, and it was not accepted.

https://www.nokia.com/bell-labs/about/dennis-m-ritchie/varar...

By the way, both Extended Pascal, Mesa/Cedar and Modula-2 have them, under the name of open arrays.

Basically it took Go, C# and others for C++ to finally get its span.

C probably never will.

trumpdong•46m ago
There's lots of UB in C-family execution models. Some of which is not actually UB because the implementation defines it - e.g. aligned DWORD-sized memory access is atomic on Windows because Microsoft said it is.

By choosing to use this language you choose to navigate the UB. Otherwise you'd be writing in Go, or Python.

It is possible to write reliable code despite the presence of UB in a language just like it's possible to drive to work every day for 20 years despite most of the directions you can point the car leading to an immediate crash. That's a needle with a much thinner eye than UB in C, and most people manage it. Mainly it means being very careful about lifetime and ownership. The Linux kernel manages it 99% of the time simply by being careful about lifetime and ownership, and that's a project with a huge number of contributors who don't intimately know each other's modules. I'm the Linux kernel you can't just say "new whatever" - you must have a plan for a lifetime of that whatever, and other people will review it.

I agree with you about std::span.

arcticbull•25m ago
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 unless even if the variable is declared static (where the members would be zeroed).

This is why the compiler is angry at the post writer, and why the reinterpret_cast is needed. Ideally if they wanted to do something with the data, they'd unbox the structure.

That's why it's not a good idea to use void* to pass arbitrary data interchangeable with bytes. It's a location, it makes no representation as to what's there and how to interact with it. Let alone who owns it.

std::span solves two problems here. One is the ownership problem. The other is that span<T> is a T[]. void* is god only knows.

The post asserts:

> The code is very clear and straightforward: you pass a pointer to the custom data structure, and its size in bytes. That’s it. Simple and clear.

This is unfortunately entirely false in C thanks to the aforementioned alignment/padding UB, and this is addressed with std::span. You'd still have to reinterpret_cast your structure to get the UB.

locknitpicker•41m ago
> I understand that people can have many things to say about C++, and I do as well, but `std::span` should have been there decades ago (...)

Decades is kind of a stretch. C++11 introduced smart pointers, and finally getting C++0x out of the door was already a major victory. Given the history of C++, it would be unrealistic to introduce something like std::span before C++17.

Meantime, some organizations are still struggling to migrate to something like C++14.

delta_p_delta_x•15m ago
> A truly zero-cost abstraction

Sadly the MSVC ABI makes std::span and std::string_view a pessimisation:

https://github.com/tringi/win64_abi_call_overhead_benchmark

https://godbolt.org/z/7baaox7re

pjmlp•12m ago
That is quite common among C developer culture, play loose and brace for impact.
voidUpdate•1h ago
> "An interesting question you may ask in C++ is: “How would you declare a function that takes a blob of memory as input?”"

> "Now, suppose that you want to pass to this function a custom structure, like this:"

You would create another function that actually works based off that structure, rather than using your first function which operates on a set of bytes in memory. That way it's readable, like they want, and type-safe

trumpdong•46m ago
I find this to be a snarky non-answer. You really think everyone should write their own memcpy for every POD type they want to memcpy?
mfost•30m ago
There's no need: there's std::copy already.

Or maybe the idea was to create a typesafe template wrapper around the generic function which is also very common and really nice. No need to create one wrapper per type, a single template should work.

themafia•1h ago
I'm not a fan of C++ precisely because of template noise but what you gain with span, in that the pointer and the length are joined together, seem to outweigh the complaints on style.

Isn't there a way to make this an alias anyways?

arcadialeak•54m ago
char* is an exception to strict aliasing rules of C++ precisely to facilitate the author's use case. You would still need a reinterpret_cast to make it work, but it's actually good because it makes the intent clearer, and the cast would have still happened either way to read the raw bytes.
quietbritishjim•38m ago
That was my first instinct too, but nothing the author said indicates they actually need non-strict aliasing. If the function had been:

   void DoSomething(void* src, void* dst, size_t numBytes);
... then it would be a different matter since maybe you want to allow src and dst to alias. Although, even then, they're still allowed to alias so long as the function accesses them both through char*, so the function signature can still use void*.

(Going deeper, non-strict aliasing applies to any pointers of the same type passed to a function. So if src and dst were both cast to float* inside the function, and if they really are both of that type (technically "an object of type float exists at the pointed-to location) then they can still alias. The char* exception is the only case that you can access a memory location through two different types of pointer and they can still alias.)

It's interesting the author mentions uint8_t. It's certainly more explicit than char, but it doesn't have the same aliasing guarantee (very strictly speaking - in practice it's almost always an alias for unsigned char or char, which does).

stinos•49m ago
> Why should people complexify and uglify their C++ code with the uint8_t pointer (or std::byte), when void* works just fine??

Fair point (although to be honest: 'complexify' feels a bit of an exaggeration here to me), but the answer to this why is simple: document and express intent clearly. The compiler gave you an error first such that you're forced to consider what you're doing. Any seasoned C++ developer seeing this knows what this reinterpret_cast means.

> Wow. With std::span the complexity-meter bumps in the red zone and goes even higher!

Same remark: yes, it's a bit more text to read, but again: to me (and many others I'm guessing) this clearly expresses intent. I also do not find it particularly hard to read. I mean, it's C++, you're likely going to encounter templates at one point or another, except in super specific software perhaps. But no-one also ever argued the C++ learning curve was easy, and trying to make it easier by refusing to use features which were added for good reasons and instead going back to constructs which are the very source of those reasons seems a bit backwards.

> As a nice addition, if you use SAL annotations, the function could be decorated a bit to help code analyzers detecting memory bugs

Some might also say it complexifies and uglifies the code. And in any case makes it non-portable on top of that.

repelsteeltje•5m ago
+1

And SAL annotations aren't even C++ proper.

arka2147483647•48m ago
The best part of void* is that it is very terse. Both in definitions, and in access.

All cpp alternatives are more wordy.

I wonder how this conversation wound go if the was an as terse, but also typesafe cpp alternative.

squirrellous•37m ago
One could argue the reinterpret_cast makes the intent more explicit which is a good thing.

That said I don’t have much against the use of void* or even char* here. If it works in C, it works in C++ just fine. std::span is not the right tool for this.

delegate•34m ago
It depends on what your function does with that memory. If the fn expects any kind of structure at that address, you and your callers are on your own, compiler can't help if the caller passes the wrong thing. Worse, acessing that memory might not immediately crash, but lead to strange side effects in your program.

Dynamic languages can handle this with reflection, but with void* you can only pray nobody makes the mistake..

delta_p_delta_x•24m ago
The blogger and the blog says:

> BTW: As a nice addition, if you use SAL annotations

> Windows C++ Programming

Not everyone will see the irony, but the Windows user-mode application and library suite and the kernel now very heavily rely on the safety mechanisms of C++ that the author calls 'complex', 'uglif[ied]', and has 'los[t] the taste for good readable code'. I'm of course referring to the Windows Implementation Library: https://github.com/microsoft/wil This is explicitly an effort from MS WinDev to make Windows C++ code safer. User-mode applications writing native Windows code can and absolutely should use it, too.

Any time I see `void*` in C++ I ring-fence it as a C-ism and make sure I reinterpret_cast. For me, a bag of bytes is `std::span<std::byte>`. void * is a memory location with no provenance, no ownership, no size information, nothing.

C likes to play fast and loose and its proponents call it 'beautiful and simple', I call it a segfault/use-after-free/double-free waiting to happen.

_the_inflator•24m ago
I think that the author is right in everything he says and yes, there is beauty in it.

However, the antithesis is also correct that there exist better solutions to solve the issues.

Both premises hold true.

I have an extensive assembler coding background on 6510, M68000, and i486. I had a very hard time accepting that something could be solved faster and more stable in a higher order language while the downside is more memory, more CPU etc.

More and more it turns out that programming languages are something accidentally read by machines and written by humans, even though this premise got destroyed lately by AI.

However, what I love about C++ is, that it has a basic canon of commands that can be used to build nearly everything while looking extremely ugly and hard to grasp if you don't read very slowly and accurately - so it is a very error prone and dangerous thing that rightfully got substituted by better constructs that allow for better distinctions as well as usage.

I could do everything in assembler (Hey Python users: you know that in the end everything ends up as machine code, don't you?) but it takes 100x times longer and is constantly reinventing the wheel.

Have you ever started to get into the intricacies of bit signs? No? Well, you should definitely, and to this day it gave me a lasting impression when I started wrapping my head around it, when I was 10 to 11 years old hacking my way into the world of assembler programming on C128.

You don't want to take every concept into consideration. You don't want to take interoperability into consideration. All the time!

You want to focus on the problem to solve, not the implications of the implementations all the time.

I am having such a blast very often using Python since it just works with much cognitive distraction about which language construct to use in order to get the machine doing what you want. It is so capable, enable it, to simply ensure within boundaries that the compiler uses the best decision given the context, which is up to analysis.

That's why I stopped using C++ or more precisely stopped any attempts and trying to be smart or fancy. I got to re-read and maintain the code month to years later and history showed, I don't marvel at how magic the line works and brutally smart I was at the time, but simply hate me for obscuring something in a line, that could be well understood if I had used 10 lines, while the compiler gives a damn anyway.

C++ is still necessary but every discussion to this day is about the point you made: every digit counts - and also which position, context etc. You got to be very prolific in order to put into a line what other put into 10.

Is it worth it? No.

In early days it was the correct decision. Memory was sparse, CPU power slow, and the language was small compared to today.

The last time I felt comfortable with a "assembler kind feeling" was with JavaScript before ES6. Peak jQuery level, with the most coolest concept only JavaScript has: Function.prototype.toString()

John Resig will have his place in my programming heroes olymp, who revealed this secret for me, and it opened my eyes for the beauty of higher order languages.

I admire C++, but so do I Python.

But I hope I won't have to ever use C++ again.

adev_•13m ago
This post post is honestly speaking a bag of garbage and ill advises:

> Some good old habit from C can still be positively used in C++, like the void* pointer and the size parameters.

That's garbage.

There is a clear interest of passing both size AND pointer in a single parameter like `std::span<std::byte>`: it bind both value together and guarantee that you do not mess with the size of your buffer.

Pass "data" and "size" parameters through a chain of 5 function calls and there is a non-null probability that you passed "other_size" instead of "size" somewhere. The pattern happens everywhere in old C codebase and is a common source of buffer overflow.

All modern languages (including freaking Golang) have a "slice" concept built in: it is not just to annoy old grumpy programmers but *because* it is a major upgrade in term of memory safety.

> It seems that some people are really losing the taste for good readable code.

If 'span<std::byte>' or 'span<char>' are unreadable for you. The problem is not span, the problem is you.

These are concepts that has been existing for decades in many programming languages. Even in conservative C++, it exists since 2014 in the GSL or in boost.

> Why should people complexify and uglify their C++ code with the uint8_t pointer (or std::byte), when void* works just fine??

Sure. Let's extend the logic: I do propose also to replace all arguments of anything with a pointer type `void`... Because after all: 'It will just works fine' right ?

Type-safety is overrated, we should all use only bytes. /irony

> Or maybe something even more complicated, like this? > template <typename T, std::size_t N> void DoSomething(std::span<T, N> data)

First that's non sense.

If you want to pass a mutable buffer of byte, the correct signature is:

`void DoSomething(std::span<std::byte> data)`

There is zero need of function template declaration and I believe the author is fully aware of that.

`span<Type,N>` is there

only* when enforcing a buffer of a given size at compile time is desirable: for vectorization or to make it explicit in the interface.

> states that the pointer points to input read-only memory (_In_reads_)

You do that by using `std::span<const std::byte>` in any C++ codebase.

The fact he brags about that as "an advantage" for separated parameter passing just show currently how little is known here.

> My Pluralsight Courses

This kind of C++ code would be straight be refused in PR in almost any serious organization.

So bragging about it on a blog while proposing some C++ teaching is audacious to say the least.

So joke aside:

To finish, I would say there is very valid criticism on `std::span<std::byte>` : - Span does not do boundary check on access by default. Which is a bad design decision in 2026. - It has an impact on compilation time due to the inclusion of the header - std::byte is annoying to work with because it is a hack around an enum instead of a proper builtins type.

But the blog post misses all these points entirely.

GentleOS – Classic operating system with a lovely retro GUI

https://github.com/luke8086/gentleos32
80•tekkertje•1h ago•9 comments

Microsoft's open source tools were hacked to steal passwords of AI developers

https://techcrunch.com/2026/06/08/microsofts-open-source-tools-were-hacked-to-steal-passwords-of-...
214•raffael_de•3h ago•90 comments

Forever Young: how one molecule can lock plants in a youthful state (2025)

https://omnia.sas.upenn.edu/story/biologist-scott-poethig-plants-never-age
47•bryanrasmussen•3h ago•23 comments

The iPhone's Last Stand

https://stratechery.com/2026/the-iphones-last-stand/
24•swolpers•1h ago•11 comments

OpenCV 5 Is Here: The Biggest Leap in Years for Computer Vision

https://opencv.org/opencv-5/
264•ternaus•3d ago•45 comments

Apple reveals new AI architecture built around Google Gemini models

https://www.macrumors.com/2026/06/08/apple-reveals-new-ai-architecture/
615•unclefuzzy•16h ago•470 comments

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

https://giodicanio.com/2026/06/05/how-to-declare-a-c-plus-plus-function-that-takes-a-blob-of-memory/
18•movd128•2d ago•25 comments

Thi.ng – open-source building blocks for computational design and art

https://thi.ng
57•nmstoker•1d ago•9 comments

Eagle Computer: The rise and fall of an early PC clone

https://dfarq.homeip.net/eagle-computer-the-rise-and-fall-of-an-early-pc-clone/
13•giuliomagnifico•2h ago•1 comments

Siri AI

https://www.apple.com/apple-intelligence/
598•0xedb•17h ago•555 comments

xAI is looking more like a datacentre REIT than a frontier lab

https://martinalderson.com/posts/xais-new-rental-business/
581•martinald•20h ago•452 comments

Show HN: Performative-UI – A react component library of design tropes

https://vorpus.github.io/performativeUI/
1000•lizhang•21h ago•187 comments

Porting the ThinkPad X61 to Coreboot

https://blog.aheymans.xyz/post/thinkpad_x61/
88•walterbell•7h ago•31 comments

An introduction to functional analysis for science and engineering

https://arxiv.org/abs/1904.02539
7•Anon84•1d ago•0 comments

EU-banned pesticides found in rice, tea and spices

https://www.foodwatch.org/en/eu-banned-pesticides-found-in-rice-tea-and-spices
433•john-titor•19h ago•215 comments

Old'aVista – The most powerful guide to the old Internet

https://oldavista.com/
114•abnercoimbre•19h ago•25 comments

MiMo-v2.5-Pro-UltraSpeed: 1T model with 1000 tokens per second

https://mimo.xiaomi.com/blog/mimo-tilert-1000tps
580•gainsurier•20h ago•428 comments

Apple Core AI Framework

https://developer.apple.com/documentation/coreai/
313•hmokiguess•16h ago•82 comments

Looking Forward to Postgres 19: Query Hints

https://www.pgedge.com/blog/looking-forward-to-postgres-19-query-hints
172•jjgreen•3d ago•28 comments

Facebook is paying people overseas promoting Alberta separatism

https://www.cbc.ca/news/canada/facebook-overseas-alberta-separtism-9.7223966
178•vrganj•5h ago•82 comments

Show HN: Gitdot – A better GitHub. Open-source, written in Rust

https://gitdot.io/
272•baepaul•18h ago•247 comments

GoGoGrandparent (YC S16) is hiring Back end Engineers

https://www.ycombinator.com/companies/gogograndparent/jobs/2vbzAw8-backend-engineer
1•davidchl•7h ago

Ask HN: What are tools you have made for yourself since the advent of AI?

320•aryamaan•17h ago•534 comments

H2JVM – A Haskell Library for Writing JVM Bytecode

https://discourse.haskell.org/t/h2jvm-a-haskell-library-for-writing-jvm-bytecode/14182
10•rowbin•2d ago•0 comments

Passing DBs through continuations

https://remy.wang/blog/cps.html
59•remywang•2d ago•8 comments

FrontierCode

https://cognition.ai/blog/frontier-code
204•streamer45•14h ago•36 comments

Ask HN: Why hasn't there been a real competitor to Ticketmaster yet?

183•mdni007•18h ago•159 comments

Why are cells small?

https://burrito.bio/essays/what-limits-a-cells-size
154•mailyk•16h ago•69 comments

Surveillance is not safety: A statement on the UK's latest threat to privacy [pdf]

https://signal.org/blog/pdfs/2026-06-08-uk-surveillance-is-not-safety.pdf
596•g0xA52A2A•15h ago•242 comments

How much do amd64 microarchitecture levels help in Go?

https://lemire.me/blog/2026/06/06/how-much-do-amd64-microarchitecture-levels-help-in-go/
61•zdw•1d ago•39 comments