C++ | May 20, 2026
C Constructs That Still Don’t Work in C++ — and a Few That Changed
A 2026 sequel to C Constructs That Don't Work in C++: what still breaks, what C++20 changed, and what C23 changed.
In 2019 I wrote a short survey of C constructs that do not work in C++. The point was not that C is sloppy or that C++ is superior. The point was that C++ is not a superset of C, and that C programmers crossing the border should know where the checkpoints are.
That advice still holds. But the border moved.
C++20 picked up a version of designated initializers. C++20 also repaired some low-level object-lifetime cases around malloc that used to be easy to describe incorrectly. C23, meanwhile, changed the old empty-parameter-list rule that made void f() mean something dangerously different in C than in C++.
The practical lesson is the same, but sharper: when you discuss C/C++ compatibility, label the language mode. “Valid C” and “valid C++” are not precise enough anymore. You often need to say C17, C23, C++17, C++20, or C++23.
I also put the examples behind this post in a small companion repository. The repository is for repeatable checks; its Compiler Explorer links are for quick diagnostics.
Compatibility matrix
Here is the short map. Details follow. The point is not just that C++ is not a superset of C. The point is that some of the canonical examples people still repeat changed under C++20 or C23, so the correct answer now depends on the language mode. This table is a map, not a substitute for the examples; on narrow screens, the sections below are easier to read than the full matrix.
... continue reading