I feel like it said a whole lot without giving me much to take action on. Like great, you summarized the current state of affairs but it doesn't make clear what I am to do about it.
To be fair, not every article is a call to action. Sometimes they exist purely for informational purposes.
Lately I've been working on an embedded system with limited access to std lib/libc and this was very interesting but I was hoping to see more information, like how can I tell if something will be supported? what are alternatives? what does implementation specific mean?
I guess I am used to HN having more in-depth articles.
Like "These Artemis 2 photos were generated by AI" is wrong but "The broadcast footage of the Apollo missions was generated by AI" is incredibly stupid and I want to understand if I'm about to engage with an incredibly stupid opinion.
I don't think it's a coincidence.
If this line wasn't written by a LLM I'll eat my hat.
I swear being online these days feels like being one of the dog handlers from the Terminator.
In some earlier articles, we used the term freestanding. We said that a freestanding implementation is one that operates without the support of a hosted operating system. Think embedded systems, OS kernels, or bare-metal environments where heap allocation, system calls, and exception support are typically unavailable. The C++ standard defines a minimal subset of the language and library that must work in such constrained environments.
But I wanted to go slightly deeper, because the term doesn’t come up much in everyday C++ — at least not until you start reading the standard more carefully or until you need to use such an implementation.
This is quite logical. If something is called freestanding, there must be an alternative — the one we’re used to. It does have a name: hosted.
To check which one you’re on, inspect the __STDC_HOSTED__ macro. A value of 1 means you’re on a hosted implementation; 0 means freestanding.
A few key differences:
main function. On a freestanding implementation, that requirement is implementation-defined.What does a program do without
main()? Start-up and termination can still be executed, including the constructors and destructors for objects with static storage duration.
Note that a vendor is not required to provide a freestanding implementation at all.
Let’s go beyond “it’s implementation-defined”. The standard does require a small but useful subset of the library to be available in freestanding environments.
You can generally rely on low-level, self-contained utilities. Headers such as <cstdint>, <cstddef>, <limits>, and <type_traits> are part of that minimal set. These provide fixed-width integer types, basic size definitions, compile-time type inspection, and numeric limits — all things that don’t depend on an operating system. Parts of <new> are available too, although that doesn’t necessarily mean you have a working heap or global allocation facilities.
What’s notably absent are components that inherently depend on OS services: no <thread>, no <filesystem>, and typically no <iostream>. Even dynamic memory and exception support are not guaranteed. Freestanding gives you the building blocks of the language and library, but not the higher-level conveniences.
Freestanding used to be very limited — almost to the point where the standard library was barely usable. That’s no longer true.
Starting from C++20 and continuing through C++23 and C++26, there has been a clear effort to expand what is available in freestanding environments. More and more headers are being made freestanding-friendly, particularly those that don’t rely on OS-level services. This includes parts of the algorithms library, various utility components, and with C++26, facilities like std::span, std::expected, std::mdspan, and smart pointer adapters like out_ptr and inout_ptr.
As a result, algorithms and utilities that used to be restricted to hosted implementations are increasingly usable without an operating system. You can write more expressive, higher-level code even in constrained environments, without having to reinvent everything from scratch.
This evolution didn’t happen by accident. There has been a strong push from domains like embedded systems and game development, where developers want both performance and better abstractions. The goal is clear: make modern C++ usable everywhere, not just on full-fledged operating systems.
Freestanding is not a niche technicality — it’s a foundational distinction in the C++ standard. It clarifies what you can actually count on when the runtime environment offers minimal guarantees: no OS, no heap, no exceptions. The fact that the standard has been steadily expanding the freestanding subset from C++20 through C++26 reflects a genuine commitment to making modern C++ viable in resource-constrained environments.
If you work on embedded software, OS kernels, or bare-metal targets, understanding what freestanding guarantees — and what it doesn’t — is directly relevant. And even if you don’t, knowing the distinction sharpens your understanding of why certain standard library components are designed the way they are, particularly around exceptions, allocation, and OS dependencies.
Do you work with freestanding implementations? What environment are you targeting?
If you liked this article, please