GCC generates essentially the same assembly for C++'s std::optional<int> with the exception that the result can't be returned in a register (a problem which will go away if the function is inlined)
Proving the point that better type system and abstractions don't necessarly produce bad Assembly, and if constexpr is used, there won't be anything on the final executable other than the actual value.
You do not need constexpr, just remove the "volatile" which I put into my example only to prevent the optimizer from specializing it: https://godbolt.org/z/fs8q3sdxK
But what matters is run-time behavior for any input. And sorry, C++'s complexity still has the effect that the code is terrible: https://godbolt.org/z/vWfjjf8rP
Except that it is much more safer to use the type system than pre-processor glue based on text replacements, with more interesting error messages than templates.
uecker · 1h ago
I don't see how it safer. I think this is just a random claim C++ people like to make without any evidence. In terms of error message, the problem is that C++ often can not produce them because due to overloading it is entirely unclear to the compiler what the intention of the code actually way. A macro-based solution also does not have ideal error message, but I do not think it is worse than C++.
pjmlp · 1h ago
It isn't a random claim, is based on years of experience fixing pre-processing code gone wrong, because whoever wrote it in first place forgotten that it is nothing more than text expansion, and then someone else completly unaware that it is a macro, ends up giving a bad set of parameters.
uecker · 52m ago
I spent also countless amount of hours fixing template code, so no I do not let your anecdotes count. There is certainly a lot of problematic macro code in C, but I do not think it is worse than C++ templates, and one can also write robust macros.
nextaccountic · 3h ago
> Here, instead of handling the error condition, I create an lvalue that points nowhere in case of an error because it then corresponds to (({ (void)0; })), relying on the null sanitizer to transform it into a run-time trap for safety.
Isn't this undefined behavior?
uecker · 31m ago
It is only undefined behavior if it is dereferenced, in which case the null sanitizer can be used to define it to trap, so safely terminate the program. But the example then also shows how you can make sure that this case is not even possible in the final program.
lmm · 3h ago
In standard C yes. But any decent C compiler will offer stronger guarantees than the minimum that the standard requires, and presumably the "null sanitizer" they're referring to is one of them.
pjmlp · 2h ago
As usual, the problem is not what they have been offering for the last decades in tooling, rather what developers actually make use of.
Unfortunely many keep needing education on such matters.
shakna · 3h ago
Maybe, but it is defined for GCC:
> You can store a null pointer in any lvalue whose data type is a pointer type. [0]
Though, I would expect a complaint from clang, and clang-tidy.
It might be more useful with a signature like maybe_divide -> maybe(int) -> maybe(int) -> maybe(int) ... and then a set of operations over maybe, and functions/macros for and_then(), or_else(), etc. It would be interesting to see how ergonomic it could get.
munchler · 41m ago
I await the first “Monads in C” tutorial with mixed feelings.
BiraIgnacio · 1h ago
I love seeing the creative ways people implement these types of, if I can say, high level abstractions in C.
Thanks for sharing
rowanG077 · 3h ago
At this point I always wonder why people who write stuff like this don't just move to a different language. You are introducing insane amounts of hidden complexity(see also the other posts on that blog). For something that just exists in other languages. Or maybe this is just a fun puzzle for the author, in which case it's totally fine.
throw-qqqqq · 3h ago
You don’t always get to choose your language. Especially in the embedded/firmware area of software development, C is the most widely available option, if not the only option besides ASM shrugs
pjmlp · 1h ago
Unless you are talking about PIC and similar CPUs, there is hardly a modern 16 bit CPU that doesn't have a C++ compiler available as well, assuming that we still consider 16 bit modern for whatever reason.
Heck I learned to program in C++, back when DR-DOS 5 was the latest version, and all I had available was 640 KB to play around, leaving aside MEMMAX.
Nowadays the only reason many embedded developers keep using C is religous.
throw-qqqqq · 1m ago
> … there is hardly a modern 16 bit CPU that doesn't have a C++ compiler
There are quite a few besides various PICs AFAIK, how modern they are is subjective I guess, and it IS mostly the weaker chips. Keil, Renesas, NXP, STMicro (STM8 MCUs used to be C only, not sure today) all sell parts where C++ is unsupported.
> Nowadays the only reason many embedded developers keep using C is religous.
I don’t completely agree, but I see where you are coming from.
The simplest tool that gets the job done is often the best IMO.
In my experience, it is much more difficult to learn C++ well enough to code safely, compared to C.
Many embedded developers are more EE than CS, so simpler software is often preferred.
I know you don’t have to use all the C++ features, all at once, but still :)
Horses for courses. I prefer C for anything embedded.
uecker · 51m ago
Religion and the garbage code C++ compilers produces, incomprehensible error message, unstable tooling, and very long compilation times.
simonask · 10m ago
What year is it, 1998? Am I going crazy?
I think you're making some extraordinary claims. I'd love to see some receipts. :-)
fuhsnn · 2h ago
The said library is a bit farther away from the C that is widely available. It relies on C23 features, GNU statement expression, GNU nested function, sanitizer runtimes, VLA types and a very niche pattern of sizeof executing its statement-expression argument; only platforms that provide latest GCC/Clang would be able to use this.
uecker · 39m ago
In the library I experiment with various things, and C23 and nested functions are not really required. And for running the code, it only relies on GNU statement expression. For bounds checking, you need need the sanitizers.
Overall, it is still far more portable than C++ or any other new language.
windward · 2h ago
It is, but the bar of what's considered too 'clever' in embedded/firmware is usually lower than this. In fact, even the ternary conditional operator is too much.
rowanG077 · 3h ago
Definitely. I still don't think you should swim against the stream. Just bite the bullet and write idiomatic C. The people who will have to debug your code in the future will thank you.
uecker · 1h ago
Because the different languages suck much more.
munchler · 39m ago
So this was inspired by Haskell, but you don’t actually think Haskell is a good language?
amiga386 · 1h ago
Quite. There's standard POSIX behaviour for this. Divide by zero and execution continues, safely, in your SIGFPE exception handler.
https://gcc.godbolt.org/z/vfzK9Toz4
https://gcc.godbolt.org/z/31o75W5xx
https://gcc.godbolt.org/z/av6a43WeY
But what matters is run-time behavior for any input. And sorry, C++'s complexity still has the effect that the code is terrible: https://godbolt.org/z/vWfjjf8rP
In C, the compiler can remove all error paths: https://godbolt.org/z/GGMcc6bxv
It's still a damned shame. Same for not being able to pass optional/unique_ptr/etc in a register.
We really need a trivially_relocatable attribute.
Isn't this undefined behavior?
Unfortunely many keep needing education on such matters.
> You can store a null pointer in any lvalue whose data type is a pointer type. [0]
Though, I would expect a complaint from clang, and clang-tidy.
[0] https://www.gnu.org/software/c-intro-and-ref/manual/html_nod...
Heck I learned to program in C++, back when DR-DOS 5 was the latest version, and all I had available was 640 KB to play around, leaving aside MEMMAX.
Nowadays the only reason many embedded developers keep using C is religous.
There are quite a few besides various PICs AFAIK, how modern they are is subjective I guess, and it IS mostly the weaker chips. Keil, Renesas, NXP, STMicro (STM8 MCUs used to be C only, not sure today) all sell parts where C++ is unsupported.
> Nowadays the only reason many embedded developers keep using C is religous.
I don’t completely agree, but I see where you are coming from.
The simplest tool that gets the job done is often the best IMO.
In my experience, it is much more difficult to learn C++ well enough to code safely, compared to C.
Many embedded developers are more EE than CS, so simpler software is often preferred.
I know you don’t have to use all the C++ features, all at once, but still :)
Horses for courses. I prefer C for anything embedded.
I think you're making some extraordinary claims. I'd love to see some receipts. :-)
Overall, it is still far more portable than C++ or any other new language.