I am still waiting for any of the alternative Rust front- or backends to allow me to bootstrap Rust on alpha, hppa, m68k and sh4 which are still lacking Rust support.
Originally, the rustc_codegen_gcc project made this promise but never fulfilled it.
> Though, the trend I'm seeing a lot of is greenfield projects just migrating their MCUs to ARM.
That’s what I would expect, too.
The Venn diagram of projects using an old architecture like alpha but also wanting to adopt a new programming language is nearly two separate circles.
The parent comment even included HPPA (PA-RISC) which almost makes me think they’re into either retro computing or they have some arbitrary completionist goal of covering all platforms.
Hi, retro computing person here. I've had a similar debate with Rust evangelists in past
Something the Rust community doesn't understand is when they shout "REWRITE IT IN RUST!" at a certain point that's simply not possible
Those mainframes your Bank runs? I'm sure they'd love to see all that "awful" FORTRAN or C or whatever other language rewritten in Rust. But if Rust as a platform doesn't support the architecture? Well then that's a non-starter
Worse still, Rust seems to basically leave anything that isn't i686/x86_64 or ARM64 as "Tier 2" or worse
This specific line in Tier 2 would send most project managers running for the hills "Tier 2 target-specific code is not closely scrutinized by Rust team(s) when modifications are made. Bugs are possible in all code, but the level of quality control for these targets is likely to be lower"
Lower level of quality control when you're trying to upgrade or refactor a legacy code base? And the target is a nuclear power plant? Or an air traffic control system? Or a bank?
The usual response from the Rust evangelists is "well then they should sponsor it to run better!" but the economics simply don't stack up. Why hire 50 Rust programmers to whip rust-m68k into shape when you can just hire 10 senior C programmers for 20% of the cost?
EDIT: Architecture, not language. I need my morning coffee
>Those mainframes your Bank runs? I'm sure they'd love to see all that "awful" FORTRAN or C or whatever other language rewritten in Rust. But if Rust as a platform doesn't support the architecture? Well then that's a non-starter
But Rust does support S390x?
>Worse still, Rust seems to basically leave anything that isn't i686/x86_64 or ARM64 as "Tier 2" or worse
Rust has an explicit documented support tier list with guarantees laid out for each level of support. Point me to a document where GCC or Clang lists out their own explicit guarantees on a platform-by-platform basis.
Because I strongly suspect that the actual "guarantees" which GCC, clang and so forth provide for most obscure architectures is not that much better than Rust, if at all - just more ambiguous. And I don't find it very likely that the level of quality control for C compilers on m68k or alpha or s390x is not, in practice, at least a bit lower than that provided for x86 and ARM.
How extensively is GCC testing on s390x, and do they hard-block merging all patches on s390x support being 100% working, verified by said test suite in a CI that runs on every submitted patchset? Or at least hard-block releases over failing tests on s390x? Do they guarantee this in a written document somewhere?
If they do, then that's great, they can legitimately claim to have something over Rust here. But if they don't, and I cannot find any reference to such a policy despite searching fairly extensively, then GCC isn't providing "tier 1"-equivalent support either.
I work for Red Hat so I'm well aware that there are people out there that care a lot about s390x support and are willing to pay for that support. But I suspect that the upstreams are much looser in what they promise, if they make any promises at all.
> This specific line in Tier 2 would send most project managers running for the hills "Tier 2 target-specific code is not closely scrutinized by Rust team(s) when modifications are made. Bugs are possible in all code, but the level of quality control for these targets is likely to be lower"
Are you operating under the assumption that the largely implicit support tiers in other compilers are better? In other words: do you think GCC’s m68k backend (to pick an arbitrary one) has been as battle-tested as their AArch64 one?
(I think the comment about evangelists is a red herring here: what Rust does is offer precison in what it guarantees, while C as an ecosystem has historically been permissive of mystery meat compilers. This IMO doesn’t scale well in a world where project maintainers are trivially accessible, since they have to now field bug reports on platforms they can’t reproduce for and never intended to support to begin with.)
> do you think GCC’s m68k backend (to pick an arbitrary one) has been as battle-tested as their AArch64 one
m68k might be a bad example to pick. I was using gcc to target m68k on netbsd in the mid 1990s. It's very battle tested.
Also, don't forget that m68k used to be in all of the macs that Apple sold at one point before they switched to powerpc (before switching to x86 and the current arm chips). You could use gcc (with mpw's libs and headers) on pre-osx (e.g. system 7) m68k macs.
> m68k might be a bad example to pick. I was using gcc to target m68k on netbsd in the mid 1990s. It's very battle tested.
That was 30 years ago! Having worked on LLVM: it's very easy for optimizing compilers to regress on smaller targets. I imagine the situation is similar in GCC.
(The underlying point is simpler: explicit is better than implicit, and all Rust is doing is front-loading the frustration from "this project was never tested on this platform but we pretend like it was" to "this platform is not well tested." That's a good thing.)
> The parent comment even included HPPA (PA-RISC) which almost makes me think they’re into either retro computing or they have some arbitrary completionist goal of covering all platforms.
Yes, retro-computing is a thing. Wouldn't it be nice to have Rust support on these platforms as well?
I am actively maintaining all of these within Debian.
Plus, there is a very vibrant community around the Motorola 68000 and SuperH CPUs thanks to the Amiga, Sega Dreamcast and many other classical computer systems and consoles.
I am not affiliated with `cg_gcc`, but I have contributed some tiny things here and there.
Currently, `cg_gcc` is within spitting distance of being able to bootstrap the compiler. There really are only 3(!) bugs that currently stop a stage 2 build.
I know for sure, because I found workarounds for them, and have a working stage 2 build. A stage 3 build requires a bit more RAM than I have, but, besides that, it is definitely possible.
Those 3 bugs are:
1. Lack of support for 128 bit SwitchInt terminators(Rust IR equivalent of switch). This is likely caused by an issue on the GCC side, since libgccjit rejects 128 bit labels provided by `cg_gcc`.
2. A semantic difference between Rust's `#[inline(always)]` and `__attribute__((always_inline)) `. In Rust `#[inline(always)]` is a hint and works on recursive functions, but the GCC equivalent is not a hint, but a gurante, and does not work on recursive function.
3. `cg_gcc` miscompiles the Rust compiler's interner code if level 3 optimzations are enabled. The Rust compiler interner is quite complex, and does a lot of fiddly unsafe things, so it is the most likely to break. The exact cause of this issue is hard to pin down, but it can be worked around(by setting a lower opt level).
If you work around those issues, `cg_gcc` is able to successfully build the Rust compiler, at least on `x86_64 Linux`. Going from that to other architectures will still take time, but it is not as far away as some might think.
Thanks for the update. I think one important issue that also needs to be resolved is adding the GCC git tree as a subproject in Rust's git tree so that in the end, it will be possible to build a Rust compiler with a rustc_codegen_gcc backend without having to resort to external repositories.
this fractalfir person is super talented. See them on the rust reddit all the time. I'm not knowledgeable on compilers at all but others seem to really like their work.
Sorry, the README was out of date. Those numbers are from the beginning of the year, and now they are:
| .NET Core tests | 1764 | 48 | 20 | 96.29% |
| C Core tests | 1712 | 71 | 8 | 95.59% |
The interop is already great via PyO3, except when people want to build the Rust part from source, but are grumpy about having to install the Rust compiler.
This hack is a Rust compiler back-end. Backends get platform-specific instructions as an input, so non-trivial generated C code won't be portable. Users will need to either get pre-generated platform-specific source, or install the Rust compiler and this back-end to generate one themselves.
They are grumpy about having to install the Rust compiler for a good reason. You can’t compile for Rust on Windows without using MSVC via Visual Studio Build Tools, which has a restrictive license.
> When targeting the MSVC ABI, Rust additionally requires an installation of Visual Studio so rustc can use its linker and libraries.
> When targeting the GNU ABI, no additional software is strictly required for basic use. However, many library crates will not be able to compile until the full MSYS2 with MinGW has been installed.
...
> Since the MSVC ABI provides the best interoperation with other Windows software it is recommended for most purposes. The GNU toolchain is always available, even if you don’t use it by default.
Rust doesn't have a runtime so it looks just like C in compiled form. c-bindgen even spits out a c header. I’m not sure what skipping C practically means even if you can argue there’s a philosophical skip happening.
You can't apply all of the hacks C programmers apply, like calling private methods, because Rust's internal ABI is different in some annoying spots.
Of course you shouldn't do that, but it's a problem rust-to-c conversion would solve.
Another reason I could think of is the desire to take something licensed in a way you don't like, written in Rust, for which you'd like to call into the private API in your production code, but don't want the legal obligations that come with modifying the source code to expose the methods the normal way.
I don't think either use case is worth the trouble, but there are theoretically some use cases where this makes sense.
It's also something I might expect someone who doesn't know much about Rust or FFIs outside of their own language might do. Not every language supports exporting methods to the C FFI, and if you're coming from one of those and looking to integrate Rust into your C you might think that translation is the only way to do it.
Most likely, it's a way rust haters can use rust code without feeling like the "other side" has won.
I'd like to write Rust, receive its safety benefits (esp borrow checker), compiler to equivalent C, and then use C's tooling on the result. Why use C's tooling?
In verification, C has piles of static analyzers, dynamic analyzers, test generators (eg KLEE), code generators (eg for parsing), a prover (Frama-C), and a certified compiler. If using a subset of these, C code can be made more secure than Rust code with more effort.
There's also many tools for debugging and maintenance made for C. I can also obfuscate by swapping out processor ISA's because C supports all of them. On the business end, they may be cheaper with lower watts.
I also have more skilled people I can hire or contract to do any of the above. One source estimated 7 million C/C++ developers worldwide. There's also a ton of books, online articles, and example code for anything we need. Rust is very strong in that last area for a new language but C/C++ will maintain an advantage, esp for low-level programming.
These are the reasons I'd use Rust if I wanted C or C++ for deployment. Likewise, I wish there was still a top-notch C++ to C compiler to get the same benefits I described with C's tooling.
Rust is much easier to learn due to C/C++ books all being paid (even cmake wants you to buy their book) whereas Rust documentation is free. I bet more and more people are choosing to learn Rust over C/C++ for this reason, and the number of C/C++ devs will be decreasing.
what a weird take to me... C has DECADES of high quality teaching material in form of books, university courses, plenty of which is freely available with a bit of searching.
And, if we discount the fact that "buying" a book is such a big hurdle, even more high quality academic text books and papers to boost; anything from embedded on the weirdest platforms, basic parsing, writing compilers, language design, high performance computing, teaching of algorithms, data structures, distributed systems, whatever!
edit: I even forgot to name operating system design plus game programming ; and of course accompanying libraries, compilers & build systems to cover all of those areas and use cases! edit2: networking, signal processing, automotive, learning about industry protocols and devices of any sort... if you explore computer science using C as your main language you are in the biggest candy store in the world with regards to what it is you want to learn about or do or implement...
> C has DECADES of high quality teaching material in form of books, university courses, plenty of which is freely available with a bit of searching.
Which means all that high quality teaching material is DECADES old. Rust development is centralised and therefore the docs are always up-to-date, unlike C/C++ which is a big big mess.
Being decades old does not make it out of date. Until a few years ago, the Linux kernel was written using C89. While it has switched to C11, the changes are fairly small such that a book on C89 is still useful. Many projects still write code against older C versions, and the C compiler supports specifying older C versions.
This is very different than Rust where every new version is abandonware after 6 weeks and the compiler does not let you specify that your code is from a specific version.
> This is very different than Rust where every new version is abandonware after 6 weeks and the compiler does not let you specify that your code is from a specific version.
Do you have any specific evidence? Rust ecosystem is known for libraries that sit on crates.io for years with no updates but they are still perfectly usable (backward-compatible) and popular. Projects usually specify their MSRV (minimum supported Rust version) in the README.
I was not asking for that. I was answering your question. You asked for evidence of rust releases being abandonware. I gave it to you. Someone else trying to ameliorate Rust releases does not change this reality.
Use language features not considered “stable rust” that are later discarded and you will learn it is abandonware very quickly. In any case, you asked for proof and now have it. You should be saying thank you instead of trying to argue.
I mean, thank you, but calling Rust abandonware just because it uses a rolling release model is misleading IMO. Also there's nothing wrong with unstable features being discarded, they're unstable.
Right, the docs never get out of date if the thing they document never changes. Can you say the same about C++ though? I’ve heard they release new versions every now and then. My robotics teacher didn’t know ‘auto’ is a thing for example.
Both C and C++ release new versions. The compilers continue to support the old versions and people continue using the old versions (less so in the case of C++). Rust’s compiler drops the old version every time it has a new release.
There is no `-std=1.85` in rust 1.86. You do get `-std=c++98` in both g++ and clang++. A book on C or C++ is still useful even decades later since the version of C or C++ described does not become abandonware at some well defined point after release, unlike Rust releases.
Given a version number MAJOR.MINOR.PATCH, increment the:
MAJOR version when you make incompatible API changes
MINOR version when you add functionality in a backward compatible manner
PATCH version when you make backward compatible bug fixes
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
C and C++ are two different languages. They are versioned by years. Rust technically does not have versions. The rust tools have versions. Basically all versions of C are binary compatible with each other. I suggest you actually learn and use C rather than asking questions since you are never going to ask the right things to understand how it works without having firsthand experience.
Only superficially. You cannot specify a past version of Rust where features existed that have since been removed by doing that. You also do not have a situation where two different incompatible languages are being accepted by the same compiler and as long as you specify which one is used, the compiler will properly compile code for it. For example, C will not accept headers with C++ exclusive features like namespaces and C++ will not accept headers with C exclusive features like variably modified types.
The only reason you see people grouping the two languages together is due to history. They are both derivatives of an ancient prestandard form of C called K&R C. They both have different standards committees who had different ideas about how to move forward from K&R C. The result is that C compilers were extended to support both, and that extension continues to this day despite the divergence between the two languages. The C standards committee accepted some of the changes the C++ committee made to K&R C, although the C++ standards committee does not reciprocate by accepting changes made by the C standards committee. This is making them increasingly different languages.
Try to spend time learning how other things work instead of posting replies that attempt to reinterpret everything people tell you through a Rust lens whenever someone is kind enough to answer your questions like you are doing here. It is like asking people how Chinese works and then telling them “English does it this way”. The “nothing matters but <insert language here>” mentality that causes that is going to annoy a large number of people from whom you would otherwise be able to learn.
Auto as it is now has been in C++ since C++11, thats more than a decade ago...
If your argument was C then sure thats a C23 feature (well the type inference type of auto ) and is reasonably new.
This is much more a reflection on youe professor than the language. C++11 was a fundamental change to the language, anyone teaching or using C++ in 2025 should have an understanding of how to to program well in a 14 year old version of said language...
Decades ols books in C most certainly is even useful in modern C++23 because you need to interact with other libraries written in C89.
When a lot of modern CS concepts wwre first discovered and studied in the 70s, there's no point arguing that old books are useless. Honestly there may be sections of old books that are useless but in the whole they are still useful.
We're talking about learning C/C++ from scratch which makes no sense to do by using a decades old book because it wouldn't teach you any modern features. Also we're not talking about computer science.
Some people want to use them, they are useful in some contexts and they often already exist in some form elsewhere, but the majority of people often do not need them.
That said, when you learn a foreign language, you do not learn every word in the dictionary and every grammatical structure. The same is true for programming. You just don't need to have a more up to date book than one on C89 to begin learning C.
A long time ago, Victor Yodaiken told me the best way to learn C was the old, K&R book. The explanations, examples, and even pitfalls were all explained well. My code worked without much fuss. That's probably because C hasn't changed much.
I ended up switching to Python for job requirements after getting through half the book. If I re-learn C, I'll go back to it. If it were C++, that would be a totally, different story since they kept piling features on over time.
Oh my... Are you serious? I'm almost triggered by this. A book about algorithms or data structures from 20 years ago has nothing more to teach? 3D game engine design from 20 years ago has nothing more to teach? No point in looking at the source code of Quake, reading k&r, and Knuth's TAOCP Volume 1 was published in 1968 so it's obviously irrelevant garbage!
I could spurr into an essay of what kind of lack of understanding you just portrayed about the world, but I won't.... I won't...
How you implement algorithms and data structures in C++/rust is semantics at best. The imperative shell of those languages are identical semantically right down to the memory model.
My copy of The C++ Programming Language for C++98 is still useful today, as is copy of The C Programming Language for C89. The idea that these books are no longer useful is absurd. Modern compilers still support those versions and the new versions are largely extensions of the old (although C++11 changed some standard library definitions). The only way you could think this is if you have zero knowledge of these languages.
There are so many free learning resources for these languages that it is ridiculous to say that you need books to learn them. The books are great, but non-essential. If you insist on reading books, there is an ancient invention called a library that you can use for free.
At a glance, the code is compatible with all C standards ever published. You are too fixated on learning the latest. The latest is largely just a superset of the earlier standards and the new features are often obscure things you are unlikely to need or want to use.
The main exceptions that you actually would want to use would be the ability to declare variables anywhere in a block and use single line // comments from C++ in C99. Most C programmers do not even know about most of the things added in newer C standards beyond those and perhaps a handful of others.
I did more research and found https://isocpp.org/get-started which appears to be the authority for C++. It states that I will need a textbook for learning C++ and includes a link to Bjarne Stroustrup "Tour of C++" Amazon page (not buying it lol). For C the situation is more complicated because there appears to be multiple organizations making standards for it, and you have to pay "CHF 221.00" to even see the standard. It kind of reminds me of the web where there is also multiple consortiums making standards and browsers hopefully implement them (except the web standards are free). In conclusion I much prefer Rust where you can just read the docs without bullshit.
Almost nobody using C (or C++ for that matter) has read the standard. The standard exists for compiler developers. If you want to read the standard, you can get copies of the drafts for free. It is an open secret that the final draft is basically verbatim with the standard that costs money. However, it is very rare that a C programmer needs to read the standard.
As for C++, there is nothing at that link that says you need a textbook to learn C++ (and the idea that you need one is ludicrous). The textbooks are suggested resources. There are plenty of free resources available online that are just as good for learning C++.
You would be better off learning C before learning C++. C++ is a huge language and its common history with C means that if you do not understand C, you are likely going to be lost with C++. If you insist on learning C++ first, here is the first search result from DuckDuckGo when I search for "learn C++":
For what it is worth, when I was young and wanted to learn C++, I had someone else tell me to learn C first. I had not intended to follow his advice, but I decided to learn C++ by taking a university class on the subject and the CS department had wisely made learning C a prerequisite for learning C++. I later learned that they had been right to do that.
After learning C++, I went through a phase where I thought C++ was the best thing ever (much like how you treat Rust). I have since changed my mind. C is far better than C++ (less is more). I am immensely proud of the C code that I have written during my life while I profoundly regret most of the C++ code that I have written. A particular startup company that I helped get off the ground after college runs their infrastructure on top of a daemon that I wrote in C++. Development of that daemon had been a disaster, with C++ features making it much harder to develop than it actually needed to be. This had been compounded by my "use all of the features" mentality, when in reality, what the software needed was a subset of features and using more language features just because I could was a mistake.
I had only been with the startup for a short time, but rejoined them as a consultant a few years ago. When I did, I saw that some fairly fundamental bugs in how operating system features were used from early development had gone unresolved for years. So much of development had been spent fighting the compiler to use various exotic language features correctly that actual bugs that were not the language's fault had gone unnoticed.
My successor had noticed that there were bugs when things had gone wrong, but put band-aids in place instead of properly fixing the bugs. For example, he used a cron job to restart the daemon at midnight instead of adding a missing `freeaddrinfo()` call and calling `accept()` until EAGAIN is received before blocking in `sigwaitinfo()`. Apparently, ~3000 lines of C++ code, using nearly every feature my younger self had known C++ to have, were too complicated for others to debug.
One of the first things I did when I returned was write a few dozen patches fixing the issues (both real ones and cosmetic ones like compiler warnings). As far as we know, the daemon is now bug free. However, I deeply regret not writing it in C in the first place. Had I written it in C, I would have spent less time fighting with the language and more time identifying mistakes I made in how to do UNIX programming. Others would have been been more likely to understand it in order to do proper fixes for bugs that my younger self had missed too.
> As for C++, there is nothing at that link that says you need a textbook to learn C++.
Sorry, it says that in their FAQ[0]. It also says "Should I learn C before I learn C++?" "Don’t bother." and proceeds to advertise a Stroustrup book[1].
> If you insist on learning C++ first, here is the first search result from DuckDuckGo when I search for "learn C++":
I don't insist on learning C++ and I even agree with you that C is better. But I have a problem with learning from non-authoritative sources, especially random websites and YouTube tutorials. I like to learn from official documentation. For C there appears to be no official documentation, and my intution tells me that, as nickpsecurity mentioned, the best way is to read the K&R book. But that brings us back to my original point that you have to buy a book.
> was the one true way (like you seem to have been with Rust)
I don't think there exists any one true way. It depends on what you do. For example I like Rust but I never really use it. I pretty much only use TypeScript.
> was the best thing ever (much like how you treat Rust)
I would actually prefer Zig over Rust but the former lacks a mature ecosystem.
> For example, they used a cron job to restart the daemon at midnight instead of adding a missing `freeaddrinfo()` call and calling `accept()` until EAGAIN is received before blocking in `sigwaitinfo()`.
This sounds like a kind of bug that would never happen in Rust because a library would handle that for you. You should be able to just use a networking library in C as well but for some reason C/C++ developers like to go as far as even implementing HTTP themselves.
> After learning C++...
Thanks for sharing your story. It's wholesome and I enjoyed reading.
> Sorry, it says that in their FAQ[0]. It also says "Should I learn C before I learn C++?" "Don’t bother." and proceeds to advertise a Stroustrup book[1].
They also would say "Don't bother" about using any other language. If you listen to them, you would never touch Rust or anything else.
> But I have a problem with learning from non-authoritative sources, especially random websites and YouTube tutorials. I like to learn from official documentation. For C there appears to be no official documentation, and my intution tells me that, as nickpsecurity mentioned, the best way is to read the K&R book. But that brings us back to my original point that you have to buy a book.
The K&R book is a great resource, although I learned C by taking a class where the textbook was "A Book On C". I later read the K&R book, although I found "A Book on C" to be quite good. My vague recollection (without pulling out my copies to review them) is that A Book On C was more instructional while the K&R book was more of a technical reference. If you do a search for "The C programming language", you might find a PDF of it on a famous archival website. Note that the K&R book refers to "The C programming language" by Kerninghan and Ritchie.
Relying on "authoritative" sources by only learning from the language authors is limiting, since they are not going to tell you the problems that the language has that everyone else who has used the language has encountered. It is better to learn programming languages from the community, who will give you a range of opinions and avoid presenting a distorted view of things.
There are different kinds of authoritative sources. The language authors are one, compiler authors are another (although this group does not teach), engineers who actually have used the language to develop production software (such as myself) would be a third and educational institutions would be a fourth. If you are curious about my background, I am ths ryao listed here:
You could go to edx.org and audit courses from world renowned institutions for free. I will do you a favor by looking through what they have and making some recommendations. For C, there really is only 1 option on edX, which is from Dartmouth. Dartmouth is a world renowned university, so it should be an excellent teacher as far as learning C is concerned. They appear to have broken a two semester sequence into 7 online courses (lucky you, I only got 1 semester at my university; there was another class on advanced UNIX programming in C, but they did not offer it the entire time I was in college). Here is what you want to take to learn C:
There is technically a certificate you can get for completing all of this if you pay, but if you just want to learn without getting anything to show for it, you can audit the courses for free.
As for C++, there are two main options on edX. One is IBM and the other is Codio. IBM is a well known titan of industry, although I had no idea that they had an education arm. On the other hand, I have never heard of Codio. Here is the IBM sequence (note that the ++ part of C++ is omitted from the URLs):
There actually are two more options on edX for C++, which are courses by Peking University and ProjectUniversity. Peking University is a world class university in China, but they only offer 1 course on edx that is 4 weeks long, so I doubt you would learn very much from it. On the other hand, I have never heard of ProjectUniversity, and their sole course on C++ is only 8 weeks long, which is not very long either. The 3 IBM courses together are 5 months long, which is what you really want.
> I pretty much only use TypeScript.
Learn C, POSIX shell scripting (or bash) and 1 functional programming language (Haskell is a popular choice). You will probably never use the functional programming language, but knowing about functional programming concepts will make you a better programmer.
> This sounds like a kind of bug that would never happen in Rust because a library would handle that for you. You should be able to just use a networking library in C as well but for some reason C/C++ developers like to go as far as even implementing HTTP themselves.
First, I was using a networking library. The C standard library on POSIX platforms is a networking library thanks to its inclusion of the Berkeley sockets API. Second, mistakes are easy to criticize in hindsight with "just use a library", but in reality, even if you use a library, you could still make a mistake, just as I did here. This code also did much more than what my description of the bug suggested. The reason for using asynchronous I/O is to be able to respond to events other than just network I/O, such as SIGUSR1. Had I not been doing that, it would not have had that bug, but it needed to respond to other things than just I/O on a socket.
I described the general idea to Grok and it produced a beautiful implementation of this in Rust using the tokio "crate". The result had the same bug that the C++ code had, because it made the understandable assumption my younger self made that 1 SIGIO = 1 connection, but that is wrong. If two connection attempts are made simultaneously from the perspective of the software, you only get 1 SIGIO. Thus, you need to call accept() repeatedly to drain the backlog before returning to listening for signals.
This logical error is not something even a wrapper library would prevent, although a wrapper library might have prevented the memory leak, but what library would I have used? Any library that wraps this would be a very thin wrapper and the use of an additional dependency that might not be usable on then future systems is a problem in itself. Qt has had two major version changes since I wrote this code. If I had used Qt 4's network library, this could have had to be rewritten twice in order to continue running on future systems. This code has been deployed on multiple systems since 2011 and it has never once needed a rewrite to work on a new system.
Finally, it is far more natural for C developers and C++ developers to use a binary format over network sockets (like I did) than HTTP. Libcurl is available when people need to use HTTP (and a wide variety of other protocols). Interestingly, an early version of my code had used libcurl for sending emails, but it was removed by my successor in favor of telling a PHP script to send the emails over a network socket (using a binary format).
> Thus, you need to call accept() repeatedly to drain the backlog before returning to listening for signals.
It's not just accept. If your socket is non-blocking the same applies to read, write, and everything else. You keep syscalling until it returns EAGAIN.
> I described the general idea to Grok and it produced a beautiful implementation of this in Rust using the tokio "crate". The result had the same bug that the C++ code had, because it made the understandable assumption my younger self made that 1 SIGIO = 1 connection, but that is wrong.
I don't know what your general idea was but tokio uses epoll under the hood (correctly), so what you are describing could only have happened if you specifically instructed grok to use SIGIO.
> Finally, it is far more natural for C developers and C++ developers to use a binary format over network sockets (like I did) than HTTP.
Designing a custom protocol is way more work than just using HTTP. <insert reasons why http + json is so popular (everyone is familiar with it blah blah blah)>.
> It's not just accept. If your socket is non-blocking the same applies to read, write, and everything else. You keep syscalling until it returns EAGAIN.
You do not call read/write on a socket that is listening for connections.
> I don't know what your general idea was but tokio uses epoll under the hood (correctly), so what you are describing could only have happened if you specifically instructed grok to use SIGIO.
That is correct. There is no other way to handle SIGUSR1 in a sane way if you are not using SIGIO. At least, there was no other way until signalfd was invented, but that is not cross platform. epoll isn't either.
> Designing a custom protocol is way more work than just using HTTP. <insert reasons why http + json is so popular (everyone is familiar with it blah blah blah)>.
You are wrong about that. The code is just sending packed structures back and forth. HTTP would overcomplicate this, since you would need to implement code to go from binary to ASCII and ASCII to binary on both ends, while just sending the packed structures avoids that entirely. The only special handling this needs is to have functions that translate the structures from host byte order into network byte order and back, to ensure that endianness is not an issue should there ever be an opposite endian machine at one end of the connection, but those were trivial to write.
Do yourself a favor and stop responding. You have no idea what you are saying and it is immensely evident to anyone who has a clue about software engineering.
> You are wrong about that. The code is just sending packed structures back and forth.
Among other things, this would only work if your client is written in a language that supports C structures.
> Do yourself a favor and stop responding. You have no idea what you are saying and it is immensely evident to anyone who has a clue about software engineering.
Says the one who didn't know how to use non-blocking sockets.
> That is correct. There is no other way to handle SIGUSR1 in a sane way if you are not using SIGIO. At least, there was no other way until signalfd was invented, but that is not cross platform. epoll isn't either.
> Among other things, this would only work if your client is written in a language that supports C structures.
Such languages are used at both ends. Otherwise, this would not have been working in production for ~13 years.
> Says the one who didn't know how to use non-blocking sockets.
Neither did you until you learned it. If you successfully begin a career in software engineering and years later, have the humility to admit the mistakes you made when starting out for the benefit of others, you will deserve to have an incompetent know it all deride you for having been so kind to admit them, just like you are doing to me here.
Anyone with a modicum of programming knowledge can write code snippets free from mistakes immediately after being told about the mistakes that would be made when given a simplified explanation of one thing that is done in production software. The problem with software engineering is that nobody tells you everything you can do wrong before you do it, and you are not writing code snippets, but production software.
> If you successfully begin a career in software engineering and years later, have the humility to admit the mistakes you made when starting out for the benefit of others, you will deserve to have an incompetent know it all deride you for having been so kind to admit them, just like you are doing to me here.
I wouldn't "deride" you if you weren't acting arrogant and calling me incompetent or whatever.
> The problem with software engineering is that nobody tells you everything you can do wrong before you do it
Maybe, but the docs definitely tell you about EAGAIN and freeing memory after you're done using it. In Rust many kinds of logical errors you could potentially have made are eliminated by the type system though. For example I wrote a news scraper in Rust and ran it locally a couple times to see that it works, and it's been running for half a year now on a VPS and I never had to touch it or restart anything.
> edit2: networking, signal processing, automotive, learning about industry protocols and devices of any sort...
I admit there is many great products that are written in C that aren’t going anywhere any time soon, notably SQLite, but there is no reason to write new software in C or C++.
I wrote a new daemon in C the other day. Plenty of people will continue to write software in C. Some will even write it in C++. There is nothing you can write that will convince the world to stop writing software in these languages. We went through this once with Java. We are going through it with Rust. We will go through it with Zig or whatever it is that people say everyone should adopt next instead of Rust and all else that came before it.
There's tools that can prove the absence of runtime errors in industrially-useful subsets of C. Frama-C, RV-Match, and Meta's Infer come to mind. That code is then usable in about anything because so much of it is written in or can call C. Until Rust has that combo, there's still a reason to use C.
Personally, I'd use both Rust and C with equivalent code. The Rust types and borrow checker give some extra assurance that C might not have. The C tooling gives extra assurance Rust doesn't have. Win, win. If I want, I can also do a certified compile or cross-compile of the Rust-equivalent, C code.
Yeah, CompCert will certify a binary for those willing to buy it or use a GPL license. Empirical testing showed it had no bugs in its middle end, unlike other compiler.
On Astree, I couldn't believe it supported all language constructs. I found this on your link:
"and is subject to the same restrictions as Astrée for C.
The high-level abstraction features and template library of C++ facilitate the design of very complex and dynamic software. Extensive use of these features may violate the established principles of safety-critical embedded software development and lead to unsatisfactory analysis times and results. The Astrée manual gives recommendations on the use of C++ features to ensure that the code can be well analyzed. For less constrained (less critical) C++ code, we recommend using the standalone RuleChecker."
So, it still does require a language subset that reduces complexity to benefit from the full analysis. They have greatly expanded what errors they catch since I first read about them. So, thanks for the link.
I do, and will, the industry does and will, for at least a few more decades. And I even enjoy doing so (with C; C++ is more forced upon me, but that'll be the case for some time to come)
That’s what I’m saying. By a few decades you and most of those alleged 7 million C/C++ developers will retire and there won’t be anyone to replace them because everyone will be using Rust or Zig or Go.
In COBOL’s case, nobody really wanted to write software in it in the first place. People used assembly or FORTRAN at the time. MBAs wanted a language corporate secretaries could use, so they made COBOL. It failed at its main purpose, but since IBM pushed it for business processing, people were coerced into writing software with it since if they did not use it, they would not have a job. As the industry developed, they stopped finding new people that they could coerce into using it and the old people started retiring/dying. Unlike COBOL adoption, C and C++ adoption occurred because software engineers wanted to use them due to merit.
> anything from embedded on the weirdest platforms, basic parsing, writing compilers, language design, high performance computing, teaching of algorithms, data structures, distributed systems, whatever
All that is language-agnostic and doesn’t necessarily have anything to do with C.
Yes, but there is material covering all of those aspects with implementations in C plus libraries plus ecosystem support! From teaching material to real world reference implementations to look at and modify and learn from.
And C maps so directly to so many concepts; it's easy to pick up any of those topics with C; and it being so loose makes it even perfect to explore many of those areas to begin with, since very quickly you're not fighting the language to let you do things.
People may learn from material that uses C for illustration purposes, but that won’t prompt them to write their own C. And don’t even mention ecosystem support in C/C++ where developers are notorious for reimplementing everything on their own because there is no package manager.
Conversely, "why does my hand-written CSV parser only support one of the 423 known variants of CSV, and it isn't the one our customer sent us yesterday?"
You kind of have a point behind dependency hell, but the flip side is that one needn't become an expert on universal CSV parsing just to have a prayer of opening them successfully.
You are greatly exaggerating the numbers, and Rust and its ecosystem are known for being stable. Are you saying everyone should write their own csv parser? Also it’s highly likely that an existing CSV library would be optimized, unlike whatever you wrote ad-hoc, so your performance argument doesn’t hold.
I'm saying package managers automate dependency hell and software is and will be less stable & more bloated as a consequence. And one should know how to write a csv parser and yes, even consider writing one if there are obvious custom restraints and it's an important part of one's project.
(and yes, numbers were exaggerated; I picked something trivial like a csv parser pulling in 89 packages for effect; the underlying principle sadly holds true)
Anyone can read a file, split it by newline and split it by comma, but what if values contain newlines or commas? How do you unescape? What about other edge cases? In Rust an existing library would handle all that, and you would also get structure mapping, type coercion, validation etc for free.
The number of dependencies does not indicate how bloated your app is. Package managers actually reduce bloat because your dependencies can have shared dependencies. The reason C programs may seem lightweight is because their number of dependencies is low, but each dependency is actually super fat, and they tend to link dynamically.
In the context of Rust it is not about "bloat" indeed. The compiler includes only used bits and nothing more. However, there are other problems, like the software supply chain security. More dependencies you have, more projects you have to track. Was there a vulnerability that affects me? Is project unmaintained and some ill factor took it over?
In C this was actually a less problem since you had to copy-paste the shared code into your program and at some level you were manually reviewing it all the time.
Also in Rust people tend to write very small libraries and that increases the number of dependencies. However, many still not follow SemVer et. al and packages tend to be unstable too. On top of additional security issues. They maybe be useful for a short time but in many cases you might need to think the lifetime of your application up to 10 years.
> However, there are other problems, like the software supply chain security.
It's not a problem with Rust specifically though. It's not unique to Rust.
> Also in Rust people tend to write very small libraries and that increases the number of dependencies. However, many still not follow SemVer et. al and packages tend to be unstable too.
Don't use random unpopular crates maintained by unknown people without reviewing the code.
The last I checked various stats (GitHub Language stats, TIOBE, etc.), Rust wasn't even in the top 10. I'm sure its adoption is increasing. However, other languages like Go seem to be doing much better. Neither will replace C++ or C anytime soon.
C/C++ will be replaced incrementally and it’s already happening. Cloudflare recently replaced nginx with their own alternative written in Rust for example.
That's nice, but a couple of Rust rewrites are not proof of a general trend.
I've been working with C for over 30 years, both professionally and a hobbyist. I have experimented with Rust but not done anything professionally with it. My gut feel is Rust is too syntactically and conceptually complex to be a practical C replacement. C++ is also has language complexity issues, however it can be adopted piecemeal and applied to most existing C code.
> My gut feel is Rust is too syntactically and conceptually complex to be a practical C replacement.
That would depend on what you use C for. But I sure can imagine people complain that Rust gets in the way of their prototyping while their C code is filled with UB and friends.
I think the "don't want to learn" is a very poor argument. I learn stuff every day, but I want want to decide myself what I learn to solve my problems, not because Rust folks think everybody has to learn Rust now. I learned a bit of Rust out of curiosity, but not so much I could do a lot with it. I do not want to learn more, because I think the language has severe flaws and and much less suitable than C for my use cases.
Does he prefer fighting libtool, make, cmake, configure, automake, autoconf and autoreconf just to add a couple libraries into his project? When I tried to use C, I wrote 10 lines of code and spent hours trying to make all that shit work. It makes me laugh when people say Rust is complicated.
Whether you need -dev packages (for headers) depends on your operating system. I run Gentoo. All headers are always on the system. Other distributions ship the headers separately in -dev packages to save space and you need to install them. You likely can install all -dev packages for everything on your system so you do not need to get the individual ones.
Too much complexity, long build times, monomorphization, lack of stability / no standard, poor portability, supply chain issues, no dynamic linking, no proper standard, not enough different implementations, etc. It is a nice language though, but I do not prefer it over C.
Eh, I'm a Rust fan, and I hate the dynamic linking situation too.
I genuinely cannot see how Rust would be able to scale to something usable for all system applications the way it is now. Is every graphical application supposed to duplicate and statically link the entire set of GNOME/GTK or KDE/Qt libraries it needs? The system would become ginormous.
The only shared library support we have now is either using the C ABI, which would make for a horrible way to use Rust dependencies, or by pinning an exact version of the Rust compiler, which makes developing for the system almost impossible.
Hopefully we'll get something with #[export] [1] and extern "crabi" [2], but until then Rust won't be able to replace many things C and C++ are used for.
> I genuinely cannot see how Rust would be able to scale to something usable for all system applications the way it is now. Is every graphical application supposed to duplicate and statically link the entire set of GNOME/GTK or KDE/Qt libraries it needs? The system would become ginormous.
I am referring to Rust scaling up to where C is now (i.e. try to remove C from the picture).
As in, if there will ever be a Rust equivalent of KDE/GNOME (e.g. maybe COSMIC), it will have similar libraries. They will have to be in Rust, and will have to be statically linked. And they will eventually grow up to be the size of KDE/GNOME (as opposed to the tiny thing COSMIC is now).
If it is any consolation, early C did not have dynamic linking either. It was added afterward. From what I understand, UNIX systems had statically linked binaries in /bin until ELF was introduced and gradually switched to dynamically linked binaries afterward.
Compiling Rust to C doesn’t simplify interoperability. Either way you’ll be calling C functions. I assume compiling Rust to C is useful if you’re targeting some esoteric platform that Rust compiler doesn’t support.
> My representation of .NETs IR maps nicely to C, which means that I was able to add support for compiling Rust to C in 2-3K LOC. Almost all of the codebase is reused, with the C and .NET specific code only present in the very last stage of compilation
Which might also allow one to use tools that work on .NET bytecode. They include verification, optimization, debugging, and other transpilers. You might also get a grant or job offer from MS Research. :)
It is a rustc backend, ie an alternative to llvm, gcc, or the cranelift backends.
It started as a .NET backend but they found that their approach could easily support C code generation as well so they added that. They do this by turning what rustc gives them into their own IR.
If the transpilation itself is bug-free, why not? For static guarantees, provided we transpile Rust code that already compiles on a normal Rust compiler, the guarantees are already checked and there, and the dynamic ones such as bounds checking can be implemented runtime in C with no problems.
this assumes the rusty guarantees are transitive. There's no reason to believe it isn't, but it'd be nice to see some sort of proof, or at least an argument for it.
Borrow checker, and more generally any type checkers, are essentially terminating programs ran during compilation process, thus safety guarantees given by them are ensured before the code is transformed into some target language.
If you mean 'no bugs in compiler' then yes. The safety of the target language doesn't matter: the output C is has an equivalent role to output machine code, those languages themselves are as unsafe as they can get, it's just that compilers output is a safer subsection of 'all programs which can be expressed in them'.
That's a problem for almost every language, not just Rust. C++ also compiles to intermediate representations, and then to machine code. Errors happen on that path. Rust just get rid of a lot of errors that could have been in the original specification (the source code).
Rust does not generate machine code itself. It uses LLVM to do that and there is no proof that the transformations done by that continue to keep the borrow checker guarantees. One just assumes with sufficient testing all bugs will be discovered.
Then the machine code generated by LLVM is not run directly by modern CPUs and is translated into internal representation first. And the future CPUs will behave like JIT-compilers with even more complex transformations.
The intermediate C code generated by this project just adds yet another transformation not fundamentally different from any of the above.
Rust does not guarantee that all bounds checks can be proven correct at compile time, so it relies on runtime bounds checks. If this does not implement the same bounds checks, then probably not.
It could fail if the generated C code triggered Undefined Behavior.
For example, signed overflow is UB in C, but defined in Rust. Generated code can't simply use the + operator.
C has type-based alias analysis that makes some type casts illegal. Rust handles alias analysis through borrowing, so it's more forgiving about type casts.
Rust has an UnsafeCell wrapper type for hacks that break the safe memory model and would be UB otherwise. C doesn't have such thing, so only uses of UnsafeCell that are already allowed by C are safe.
I have workarounds for all "simple" cases of UB in C(this is partially what the talk is about). The test code is running with `-fsantize=undefined`, and triggers no UB checks.
There are also escape hatches for strict aliasing in the C standard - mainly using memcpy for all memory operations.
That's not the same, and not what pornel is talking about. The x86 ADD instruction has a well-defined behavior on overflow, and i32 + i32 in Rust will usually be translated to an ADD instruction, same as int + int in C. But a C compiler is allowed to assume that a signed addition operation will never overflow (the dreaded Undefined Behavior), while a Rust compiler must not make that assumption. This means that i32 + i32 must not be translated to int + int.
For example, a C compiler is allowed to optimize the expression a+1<a to false (if a is signed), but a Rust compiler isn't allowed to do this.
This would have to go into one big unsafe block for any nontrivial program. C doesn’t convey all of the explicit things you need to know about the code to make it even compile in Rust.
I once implemented a WASM to Rust compiler that due to WASM's safety compiles to fully safe Rust. So I was able to compile C -> WASM -> Rust and ended up with fully safe code. Though of course, just like in WASM, the C code is still able to corrupt its own linear memory, just can't escape the "sandbox". Firefox has employed a similar strategy: https://hacks.mozilla.org/2020/02/securing-firefox-with-weba...
Mark Russinovich recently gave a talk at a UK Rust conference that mentioned Microsoft's internal attempts at large scale C->Rust translation, https://www.youtube.com/watch?v=1VgptLwP588
Tools like those exist. The problem with them is that they use unsafe blocks a lot, and the code usually isn't very idiomatic. Translating global variable state machines into more idiomatic Rust state machines based on things like named enums, for instance, would be very difficult.
With the help of powerful enough AI we might be able to get a tool like this, but as AI still very much sucks at actually doing what it's supposed to do, I don't think we're quite ready yet. I imagine you'd also need enough memory to keep the entire C and Rust code base inside of your context window, which would quickly require very expensive hardware once your code grows beyond a certain threshold. If you don't, you end up like many code assisting LLMs, generating code independently that's incompatible with itself.
Still, if you're looking to take a C project and extend it in Rust, or perhaps slowly rewrite it piece by piece, https://c2rust.com/ is ready for action.
1. It means you don't need C code & a C compiler in your project any more, which simplifies infrastructure. E.g. cross compiling is easier without any C.
2. You can do LTO between Rust and the C->Rust code so in theory you could get a smaller & faster executable.
3. In most cases it is the first step to a gradual rewrite in idiomatic Rust.
Because of the niceties of Rust, combined with the widespread compatibility and architecture support of gcc / C compilers in general?
Rust is a modern language, with package management, streamlined integrated build/testing tools, much less cruft, and lots of high-level features and syntax that people actually like. C is neat but complex codebases benefit from modern languages that help in building robust abstractions while still maintaining the speed of C. Not to mention, of course, the borrow checker and memory safety.
It seems like there's a healthy dose of "because it can be done" in play here, but also because there are a lot of platforms that are not supported by Rust where a Rust-to-C converter that generated standard-enough code could be used to bridge the gap.
I think there are probably C compilers for more platforms than there are rust compilers. So, if you want to compile your rust project on some obscure platform that doesn’t have a rust compiler for it yet, you could compile to C and then compile the resulting C code for that platform?
“ The project aims to provide a way to easily use Rust libraries in .NET. It comes with a Rust/.NET interop layer, which allows you to easily interact with .NET code from Rust
[…]
While .NET is the main focus of my work, this project can also be used to compile Rust to C, by setting the C_MODE enviroment flag to 1.
This may seem like a strange and unrelated feature, but the project was written in such a way that this is not only possible, but relatively easy.”
It also doesn’t mention for which version of C it produces code. That may or may not hinder attempts to use this to run rust on obscure platforms.
The README is slightly out of date, sorry. Supporting old platforms is one of the goals.
Truth be told, the support for C was at first added as a proff-of-concept that a Rust to C compiler is possible. But it worked surprisingly well, so I just decided to roll with it, and see where it takes me.
My policy in regards to C version is: I want to be as close to ANSI C as possible. So, I avoid modern C features as much as I can. I don't know if full compatibility is achievable, but I certainly hope so. Only time will tell.
Some simpler pieces of Rust work just fine with ANSI C compilers, but more complex code breaks(eg. due to unsupported intrinsics). If I will be able to solve that(+ some potential soundness issues) then I'll be able to use ANSI C.
This is a fairly common technique in compiler construction and programming language research: Don't try to emit some machine code, instead emit C or an IR for clang or GCC. And suddenly your little research language (not that rust is one) is executable on many, many platforms, can rely on optimizations the compilers can do, has potential access to debug handling, ..
Regarding the other way, I guess a lot of (practically) legal C wouldn't compile to Rust at all due to the language's restrictions and C's laxness, while I think all Rust could be translated to C.
They are amazing machines designed for fault tolerance (99.999% reliability). The Wikipedia article below has design details for how many generations were made. HP bought them.
I think it would be useful in open-source, fault tolerance to copy one of their designs with SiFive's RISC-V cores. They could use a 20 year old approach to dodge patent issues. Despite its age, the design would probably be competitive, maybe better, than FOSS clusters on modern hardware in fault tolerance.
One might also combine the architecture with one of the strong-consistency DR'S, like FoundationDB or CochroachDB, with modifications to take advantage of its custom hardware. At the local site, the result would be easy scaling of a system whose nodes appeared to never fail. The administrator still has to do regular maintenance, though, as the system reports component failures which it works around.
Not only does NonStop not support Rust, but apparently they failed to port gcc to it, even. So compiling Rust straight to C itself is pretty much the only option there.
To use rust in places where you can only use C. I imagine there are quite a few obscure microcontrollers that would benefit greatly from this pipeline.
Hell, you might finally be able to get Rust into the Linux kernel. Just don't tell them the code was originally written in Rust to calm their nerves.
Game consoles generally only offer clang as a possibility for compiler. If you can compile rust to C, then you can finally use rust for videogames that need to run everywhere.
If I see something like "At least on Linux, long and long long are both 64 bits in size." my skin starts to crawl. Not only that, but GCC defines __builtin_popcount() with unsigned int / long / long long, respective, i.e. even in the text it should be mentioned correctly (unless a different compiler uses signed types there ... ugh). The call is done with unsigned, using uint64_t as a type-cast, but using a fixed __builtin_popcountl() which translates to unsigned long. There are systems where this will fail, i.e. the only safe bet to use here is __builtin_popcountll() as this will cover at least 64 bit wide arguments.
Also, if a * b overflows within the result type, it is an undefined behavior according to the C standard, so this overflow check is at least not properly portable, either, and the shown code for that is actually buggy because the last A1 has to be A0.
Since signed multiplication is bitwise-equivalent to unsigned multiplication, I use unsigned multiplication to emulate UB-free signed multiplication. The signed variant of this overflow check is a bit harder to read because of that, but it still works just fine.
As for using `__builtin_popcountll` instead - you are right, my mistake. Thanks for pointing that out :).
I did not use the word "unsigned" before long long for the sake of readability - I know that repeating a word so many times can make it harder to parse for some folk. The project itself uses the correct types in the code, I was just kind of loose with the language in the article itself. My bad, I'll fix that and be a bit more accurate.
Yes, the C and C++ unsigned types are analogous to Rust's Wrapping<u8> Wrapping<u16> Wrapping<u32> and so on, except that their size isn't nailed down by the ISO document.
I clicked through to the project at
https://github.com/FractalFir/rustc_codegen_clr - from a quick glance at it, with 1.8k stars and 17 contributors, it deserves a better treatment than a passive—aggressive dismissal like this as a top comment.
Right, and that probably should have been the link rather than some in-process thoughts about popcount or w/e. Sorry for not figuring it out and clicking around effectively.
The linked article was mostly meant for people already lossely familiar with the project, but it seems it escaped its intended audience.
I do have a whole bunch of articles about the project on my website, going trough the entire journey of the project, from its start as a Rust to .NET compiler, to the current state.
I should have probably linked the previous articles in this one - I'll add that to my website. I'll also look into adding some more context to the articles next time.
I guess the complaint was more about your fans updooting stuff, so apologies if it sounded like I was shitting on this. Cool project, and I really am awaiting the presentation/writeup.
Yeah, exactly. Here on a website called 'Hacker News', we're only interested in projects when they're feature complete and mature enough for production deployment, not before. (/s)
I'm not convinced that it’s worth spending any time supporting most proprietary systems. Maybe not even Windows, but especially the really expensive ones.
> You shouldn't spend your own effort; you should make it clear that you're open to users of such systems contributing.
In practice you can't really draw a line between those two things.
I don't know the end result, but I remember a discussion of how implementing parts of Git in Rust would be a problem because NonStop, a currently supported platform, has no Rust support. Of course the sane response would be "screw NonStop then", but having accepted contributions to make NonStop a supported platform that isn't an easy path to take.
That is absolutely true but exotic platforms are also fun to investigate and you can learn a lot. So I'd say you shouldn't spend your own effort if you don't want to but I am glad fractalfir did and I am looking forward to the his RustWeekNL presentation.
I'm always convinced that people will pick up arbitrary projects that they are interested in and might not necessarily lead to a new pitch for venture capital or the next unicorn.
How is this not dangerous? How can one be assured that all of the compile-time safety features of the Rust compiler are still in effect? Handwaving does not help.
Machine code is generally much safer than C - e.g. it usually lacks undefined behaviour. If you're unsure about how a given piece of machine code behaves, it's usually sufficient to test it empirically.
Not true on RISC-V. That's full of undefined behaviour.
But anyway this is kind of off-topic. I think OutOfHere was imagining that this somehow skips the type checking and borrow checking steps which of course it doesn't.
What's all that undefined behavior? Closest I can think of is executing unsupported instructions, but you have to mess up pretty hard for that to happen, and you're not gonna get predictable behavior here anyway (and sane hardware will trap of course; and executing random memory as instructions is effectively UB on any architecture).
(there's a good bit of unpredictable behavior (RVV tail-agnostic elements, specific vsetvl result), but unpredictable behavior includes any multithreading in any architecture and even Rust (among other languages))
Fair point on CSRs, though I'd count that as a subset of unsupported/not-yet-specified instructions; pretty sure all of the "reserved"s in the spec are effectively not-yet-defined instructions too, which'll have equivalents in any architecture with encoding space left for future extensions, not at all unique to RISC-V.
But yeah, no try-running-potentially-unsupported-things-to-discover-what-is-supported; essentially a necessary property for an open ISA as there's nothing preventing a vendor from adding random custom garbage in encoding space they don't use.
Yeah I guess the difference is once an instruction/CSR has been defined in x86 or ARM the only two options are a) it doesn't exist, and b) it's that instruction.
In RISC-V it can be anything even after it has been defined.
Actually... I say that, but they do actually reserve spaces in the CSR and opcode maps specifically for custom extensions so in theory they could say it's only undefined behaviour in those spaces and then you would be able to probe in the standard spaces. Maybe.
I think they just don't want people probing though, even though IMO it's the most expedient solution most of the time. Otherwise you have to go via an OS syscall, through the firmware and ACPI tables, device tree or mconfigptr (when they eventually define that).
On getting supported extension status - there's a C API spec that could potentially become an option for an OS-agnostic way: https://github.com/riscv-non-isa/riscv-c-api-doc/blob/main/s.... libc already will want to call whatever OS thing to determine what extensions it can use for memcpy etc, so taking the results from libc is "free".
Not any different from C - a given C compiler + platform will behave completetly deterministically and you can test the output and see what it does, regardless of UB or not.
> a given C compiler + platform will behave completetly deterministically and you can test the output and see what it does, regardless of UB or not.
Sure[1], but that doesn't mean it's safe to publish that C code - the next version of that same compiler on that same platform might do something very different. With machine code (especially x86, with its very friendly memory model) that's unlikely.
(There are cases like unused instructions becoming used in never revisions of a processor - but you wouldn't be using those unused instructions in the first place. Whereas it's extremely common to have C code that looks like it's doing something useful, and is doing that useful thing when compiled with a particular compiler, but is nevertheless undefined behaviour that will do something different in a future version)
[1] Build nondeterminism does exist, but it's not my main concern
CPUs get microcode updates all the time, too. Nothing is safe from bitrot unless you’re dedicated to 100% reproducible builds and build on the exact same box you’re running on. (…I’m not, for the record - but the more, the merrier.)
To fix bugs, sure. They don't generally get updates that contain new optimizations that radically break existing machine code, justifying this by saying that the existing code violated some spec.
Extremely unlikely. CPU bugs generally halt the CPU or fail to write the result or something like that. The Pentium FDIV bug where it would give a plausible but wrong result was a once in a lifetime thing.
Maybe. But when carefully investigated, the overwhelming majority of C code does in fact use undefined behaviour, and there is no practical way to verify that any given code doesn't.
I am still waiting for any of the alternative Rust front- or backends to allow me to bootstrap Rust on alpha, hppa, m68k and sh4 which are still lacking Rust support.
Originally, the rustc_codegen_gcc project made this promise but never fulfilled it.
> to allow me to bootstrap Rust on alpha, hppa, m68k and sh4
Do you actually use all four of those platforms, or is this an arbitrary threshold for what you consider a complete set of platform support?
They're still common (except for alpha) platforms in some market segment specific corners of embedded development. So, maybe for those purposes?
Though, the trend I'm seeing a lot of is greenfield projects just migrating their MCUs to ARM.
> Though, the trend I'm seeing a lot of is greenfield projects just migrating their MCUs to ARM.
That’s what I would expect, too.
The Venn diagram of projects using an old architecture like alpha but also wanting to adopt a new programming language is nearly two separate circles.
The parent comment even included HPPA (PA-RISC) which almost makes me think they’re into either retro computing or they have some arbitrary completionist goal of covering all platforms.
Hi, retro computing person here. I've had a similar debate with Rust evangelists in past
Something the Rust community doesn't understand is when they shout "REWRITE IT IN RUST!" at a certain point that's simply not possible
Those mainframes your Bank runs? I'm sure they'd love to see all that "awful" FORTRAN or C or whatever other language rewritten in Rust. But if Rust as a platform doesn't support the architecture? Well then that's a non-starter
Worse still, Rust seems to basically leave anything that isn't i686/x86_64 or ARM64 as "Tier 2" or worse
This specific line in Tier 2 would send most project managers running for the hills "Tier 2 target-specific code is not closely scrutinized by Rust team(s) when modifications are made. Bugs are possible in all code, but the level of quality control for these targets is likely to be lower"
Lower level of quality control when you're trying to upgrade or refactor a legacy code base? And the target is a nuclear power plant? Or an air traffic control system? Or a bank?
The usual response from the Rust evangelists is "well then they should sponsor it to run better!" but the economics simply don't stack up. Why hire 50 Rust programmers to whip rust-m68k into shape when you can just hire 10 senior C programmers for 20% of the cost?
EDIT: Architecture, not language. I need my morning coffee
>Those mainframes your Bank runs? I'm sure they'd love to see all that "awful" FORTRAN or C or whatever other language rewritten in Rust. But if Rust as a platform doesn't support the architecture? Well then that's a non-starter
But Rust does support S390x?
>Worse still, Rust seems to basically leave anything that isn't i686/x86_64 or ARM64 as "Tier 2" or worse
Rust has an explicit documented support tier list with guarantees laid out for each level of support. Point me to a document where GCC or Clang lists out their own explicit guarantees on a platform-by-platform basis.
Because I strongly suspect that the actual "guarantees" which GCC, clang and so forth provide for most obscure architectures is not that much better than Rust, if at all - just more ambiguous. And I don't find it very likely that the level of quality control for C compilers on m68k or alpha or s390x is not, in practice, at least a bit lower than that provided for x86 and ARM.
We made s390x builds of all our tools (http://www.auxon.io) for an early customer that insisted on running their org on a leased machine from IBM.
It was actually a pretty good experience. It mostly just worked.
> But Rust does support S390x?
It's not a tier-1 target though.
And?
How extensively is GCC testing on s390x, and do they hard-block merging all patches on s390x support being 100% working, verified by said test suite in a CI that runs on every submitted patchset? Or at least hard-block releases over failing tests on s390x? Do they guarantee this in a written document somewhere?
If they do, then that's great, they can legitimately claim to have something over Rust here. But if they don't, and I cannot find any reference to such a policy despite searching fairly extensively, then GCC isn't providing "tier 1"-equivalent support either.
I work for Red Hat so I'm well aware that there are people out there that care a lot about s390x support and are willing to pay for that support. But I suspect that the upstreams are much looser in what they promise, if they make any promises at all.
> This specific line in Tier 2 would send most project managers running for the hills "Tier 2 target-specific code is not closely scrutinized by Rust team(s) when modifications are made. Bugs are possible in all code, but the level of quality control for these targets is likely to be lower"
Are you operating under the assumption that the largely implicit support tiers in other compilers are better? In other words: do you think GCC’s m68k backend (to pick an arbitrary one) has been as battle-tested as their AArch64 one?
(I think the comment about evangelists is a red herring here: what Rust does is offer precison in what it guarantees, while C as an ecosystem has historically been permissive of mystery meat compilers. This IMO doesn’t scale well in a world where project maintainers are trivially accessible, since they have to now field bug reports on platforms they can’t reproduce for and never intended to support to begin with.)
> do you think GCC’s m68k backend (to pick an arbitrary one) has been as battle-tested as their AArch64 one
m68k might be a bad example to pick. I was using gcc to target m68k on netbsd in the mid 1990s. It's very battle tested.
Also, don't forget that m68k used to be in all of the macs that Apple sold at one point before they switched to powerpc (before switching to x86 and the current arm chips). You could use gcc (with mpw's libs and headers) on pre-osx (e.g. system 7) m68k macs.
> m68k might be a bad example to pick. I was using gcc to target m68k on netbsd in the mid 1990s. It's very battle tested.
That was 30 years ago! Having worked on LLVM: it's very easy for optimizing compilers to regress on smaller targets. I imagine the situation is similar in GCC.
(The underlying point is simpler: explicit is better than implicit, and all Rust is doing is front-loading the frustration from "this project was never tested on this platform but we pretend like it was" to "this platform is not well tested." That's a good thing.)
> The parent comment even included HPPA (PA-RISC) which almost makes me think they’re into either retro computing or they have some arbitrary completionist goal of covering all platforms.
Yes, retro-computing is a thing. Wouldn't it be nice to have Rust support on these platforms as well?
I am actively maintaining all of these within Debian.
Plus, there is a very vibrant community around the Motorola 68000 and SuperH CPUs thanks to the Amiga, Sega Dreamcast and many other classical computer systems and consoles.
"m68k-unknown-linux-gnu" was merged as a Tier-3 target for Rust, wasn't it? [0]
[0] https://github.com/rust-lang/compiler-team/issues/458
Yes, it was me that did the work on the Rust side. It doesn't work yet though as progress on the LLVM side is very slow.
Did they abandon that goal? Last I heard it was still under development.
Well, the promise was that rustc_codegen_gcc would reach its goals very quickly which is why several people dismissed projects such as gccrs.
But it turns out that rustc_codegen_gcc still hasn't delivered and it seems the project has fallen asleep.
I am not affiliated with `cg_gcc`, but I have contributed some tiny things here and there.
Currently, `cg_gcc` is within spitting distance of being able to bootstrap the compiler. There really are only 3(!) bugs that currently stop a stage 2 build.
I know for sure, because I found workarounds for them, and have a working stage 2 build. A stage 3 build requires a bit more RAM than I have, but, besides that, it is definitely possible.
Those 3 bugs are: 1. Lack of support for 128 bit SwitchInt terminators(Rust IR equivalent of switch). This is likely caused by an issue on the GCC side, since libgccjit rejects 128 bit labels provided by `cg_gcc`. 2. A semantic difference between Rust's `#[inline(always)]` and `__attribute__((always_inline)) `. In Rust `#[inline(always)]` is a hint and works on recursive functions, but the GCC equivalent is not a hint, but a gurante, and does not work on recursive function. 3. `cg_gcc` miscompiles the Rust compiler's interner code if level 3 optimzations are enabled. The Rust compiler interner is quite complex, and does a lot of fiddly unsafe things, so it is the most likely to break. The exact cause of this issue is hard to pin down, but it can be worked around(by setting a lower opt level).
If you work around those issues, `cg_gcc` is able to successfully build the Rust compiler, at least on `x86_64 Linux`. Going from that to other architectures will still take time, but it is not as far away as some might think.
Thanks for the update. I think one important issue that also needs to be resolved is adding the GCC git tree as a subproject in Rust's git tree so that in the end, it will be possible to build a Rust compiler with a rustc_codegen_gcc backend without having to resort to external repositories.
rust still doesn't even support OpenBSD on x86_64...
Do you mean x86 (as in 32bit)? Because I'm fairly sure that there's a Rust package available on x86_64 ( and aarch64, riscv64, sparc64 and powerpc64).
Rust has Tier 3 support for OpenBSD on x86_64
this fractalfir person is super talented. See them on the rust reddit all the time. I'm not knowledgeable on compilers at all but others seem to really like their work.
I think they’re pretty young too. Hoping for a bright future ahead of them!
"Most components of std are about 95% working in .NET, and 80% working in C."
.NET
Core tests 1662 39 12 97.02%
C
Core tests 1419 294 82.83%
Missing from HN title: The "95%" pass rate only applies to .NET. For GCC/Clang it is only "80%".
Sorry, the README was out of date. Those numbers are from the beginning of the year, and now they are: | .NET Core tests | 1764 | 48 | 20 | 96.29% | | C Core tests | 1712 | 71 | 8 | 95.59% |
Has anyone tested this project on NetBSD.
https://github.com/dotnet/coreclr/pull/4504/files
Any reason why it would not work.
Lots of interesting use cases for this. First one that comes to mind is better interop with other languages, like Python.
The interop is already great via PyO3, except when people want to build the Rust part from source, but are grumpy about having to install the Rust compiler.
This hack is a Rust compiler back-end. Backends get platform-specific instructions as an input, so non-trivial generated C code won't be portable. Users will need to either get pre-generated platform-specific source, or install the Rust compiler and this back-end to generate one themselves.
They are grumpy about having to install the Rust compiler for a good reason. You can’t compile for Rust on Windows without using MSVC via Visual Studio Build Tools, which has a restrictive license.
You can use the GNU ABI instead, if you don't want to use the Visual Studio Build Tools.
https://rust-lang.github.io/rustup/installation/windows.html
> When targeting the MSVC ABI, Rust additionally requires an installation of Visual Studio so rustc can use its linker and libraries.
> When targeting the GNU ABI, no additional software is strictly required for basic use. However, many library crates will not be able to compile until the full MSYS2 with MinGW has been installed.
...
> Since the MSVC ABI provides the best interoperation with other Windows software it is recommended for most purposes. The GNU toolchain is always available, even if you don’t use it by default.
What does this gain you that you can't already do with `extern "c"` functions from rust?
’Extern c’ still uses Rust. You want to skip Rust and call C from other languages directly.
Rust doesn't have a runtime so it looks just like C in compiled form. c-bindgen even spits out a c header. I’m not sure what skipping C practically means even if you can argue there’s a philosophical skip happening.
You can't apply all of the hacks C programmers apply, like calling private methods, because Rust's internal ABI is different in some annoying spots.
Of course you shouldn't do that, but it's a problem rust-to-c conversion would solve.
Another reason I could think of is the desire to take something licensed in a way you don't like, written in Rust, for which you'd like to call into the private API in your production code, but don't want the legal obligations that come with modifying the source code to expose the methods the normal way.
I don't think either use case is worth the trouble, but there are theoretically some use cases where this makes sense.
It's also something I might expect someone who doesn't know much about Rust or FFIs outside of their own language might do. Not every language supports exporting methods to the C FFI, and if you're coming from one of those and looking to integrate Rust into your C you might think that translation is the only way to do it.
Most likely, it's a way rust haters can use rust code without feeling like the "other side" has won.
Not GP, but what is the point of touching Rust at all then?
I'd like to write Rust, receive its safety benefits (esp borrow checker), compiler to equivalent C, and then use C's tooling on the result. Why use C's tooling?
In verification, C has piles of static analyzers, dynamic analyzers, test generators (eg KLEE), code generators (eg for parsing), a prover (Frama-C), and a certified compiler. If using a subset of these, C code can be made more secure than Rust code with more effort.
There's also many tools for debugging and maintenance made for C. I can also obfuscate by swapping out processor ISA's because C supports all of them. On the business end, they may be cheaper with lower watts.
I also have more skilled people I can hire or contract to do any of the above. One source estimated 7 million C/C++ developers worldwide. There's also a ton of books, online articles, and example code for anything we need. Rust is very strong in that last area for a new language but C/C++ will maintain an advantage, esp for low-level programming.
These are the reasons I'd use Rust if I wanted C or C++ for deployment. Likewise, I wish there was still a top-notch C++ to C compiler to get the same benefits I described with C's tooling.
Rust is much easier to learn due to C/C++ books all being paid (even cmake wants you to buy their book) whereas Rust documentation is free. I bet more and more people are choosing to learn Rust over C/C++ for this reason, and the number of C/C++ devs will be decreasing.
what a weird take to me... C has DECADES of high quality teaching material in form of books, university courses, plenty of which is freely available with a bit of searching.
And, if we discount the fact that "buying" a book is such a big hurdle, even more high quality academic text books and papers to boost; anything from embedded on the weirdest platforms, basic parsing, writing compilers, language design, high performance computing, teaching of algorithms, data structures, distributed systems, whatever!
edit: I even forgot to name operating system design plus game programming ; and of course accompanying libraries, compilers & build systems to cover all of those areas and use cases! edit2: networking, signal processing, automotive, learning about industry protocols and devices of any sort... if you explore computer science using C as your main language you are in the biggest candy store in the world with regards to what it is you want to learn about or do or implement...
> C has DECADES of high quality teaching material in form of books, university courses, plenty of which is freely available with a bit of searching.
Which means all that high quality teaching material is DECADES old. Rust development is centralised and therefore the docs are always up-to-date, unlike C/C++ which is a big big mess.
Being decades old does not make it out of date. Until a few years ago, the Linux kernel was written using C89. While it has switched to C11, the changes are fairly small such that a book on C89 is still useful. Many projects still write code against older C versions, and the C compiler supports specifying older C versions.
This is very different than Rust where every new version is abandonware after 6 weeks and the compiler does not let you specify that your code is from a specific version.
> This is very different than Rust where every new version is abandonware after 6 weeks and the compiler does not let you specify that your code is from a specific version.
Do you have any specific evidence? Rust ecosystem is known for libraries that sit on crates.io for years with no updates but they are still perfectly usable (backward-compatible) and popular. Projects usually specify their MSRV (minimum supported Rust version) in the README.
https://endoflife.date/rust
Are you asking for LTS releases? https://ferrocene.dev/en/
I was not asking for that. I was answering your question. You asked for evidence of rust releases being abandonware. I gave it to you. Someone else trying to ameliorate Rust releases does not change this reality.
Well “abandonware” is a strange way to call that because nothing is actually abandoned.
Use language features not considered “stable rust” that are later discarded and you will learn it is abandonware very quickly. In any case, you asked for proof and now have it. You should be saying thank you instead of trying to argue.
I mean, thank you, but calling Rust abandonware just because it uses a rolling release model is misleading IMO. Also there's nothing wrong with unstable features being discarded, they're unstable.
The description is accurate compared to what you get from other more established systems languages.
> Being decades old does not make it out of date.
Right, the docs never get out of date if the thing they document never changes. Can you say the same about C++ though? I’ve heard they release new versions every now and then. My robotics teacher didn’t know ‘auto’ is a thing for example.
Both C and C++ release new versions. The compilers continue to support the old versions and people continue using the old versions (less so in the case of C++). Rust’s compiler drops the old version every time it has a new release.
There is no `-std=1.85` in rust 1.86. You do get `-std=c++98` in both g++ and clang++. A book on C or C++ is still useful even decades later since the version of C or C++ described does not become abandonware at some well defined point after release, unlike Rust releases.
I'm confused. Rust uses semantic versioning:
Given a version number MAJOR.MINOR.PATCH, increment the:
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.What kind of versioning scheme does C/C++ use?
C and C++ are two different languages. They are versioned by years. Rust technically does not have versions. The rust tools have versions. Basically all versions of C are binary compatible with each other. I suggest you actually learn and use C rather than asking questions since you are never going to ask the right things to understand how it works without having firsthand experience.
> C and C++ are two different languages. They are versioned by years.
That sounds like Rust editions.
Only superficially. You cannot specify a past version of Rust where features existed that have since been removed by doing that. You also do not have a situation where two different incompatible languages are being accepted by the same compiler and as long as you specify which one is used, the compiler will properly compile code for it. For example, C will not accept headers with C++ exclusive features like namespaces and C++ will not accept headers with C exclusive features like variably modified types.
The only reason you see people grouping the two languages together is due to history. They are both derivatives of an ancient prestandard form of C called K&R C. They both have different standards committees who had different ideas about how to move forward from K&R C. The result is that C compilers were extended to support both, and that extension continues to this day despite the divergence between the two languages. The C standards committee accepted some of the changes the C++ committee made to K&R C, although the C++ standards committee does not reciprocate by accepting changes made by the C standards committee. This is making them increasingly different languages.
Try to spend time learning how other things work instead of posting replies that attempt to reinterpret everything people tell you through a Rust lens whenever someone is kind enough to answer your questions like you are doing here. It is like asking people how Chinese works and then telling them “English does it this way”. The “nothing matters but <insert language here>” mentality that causes that is going to annoy a large number of people from whom you would otherwise be able to learn.
Auto as it is now has been in C++ since C++11, thats more than a decade ago...
If your argument was C then sure thats a C23 feature (well the type inference type of auto ) and is reasonably new.
This is much more a reflection on youe professor than the language. C++11 was a fundamental change to the language, anyone teaching or using C++ in 2025 should have an understanding of how to to program well in a 14 year old version of said language...
> Auto as it is now has been in C++ since C++11, thats more than a decade ago...
> anyone teaching or using C++ in 2025 should have an understanding of how to to program well in a 14 year old version of said language...
If the current year is 2025 then 14 years ago is 2011 which is not that long ago.
> If your argument was C then sure thats a C23 feature (well the type inference type of auto ) and is reasonably new.
Grandparent comment is arguing that Linux was written in C89 until a few days ago so decades old books on C aren't actually outdated.
Decades ols books in C most certainly is even useful in modern C++23 because you need to interact with other libraries written in C89.
When a lot of modern CS concepts wwre first discovered and studied in the 70s, there's no point arguing that old books are useless. Honestly there may be sections of old books that are useless but in the whole they are still useful.
We're talking about learning C/C++ from scratch which makes no sense to do by using a decades old book because it wouldn't teach you any modern features. Also we're not talking about computer science.
You do not need to know about modern features to write code in C. This is part of computer science.
> You do not need to know about modern features to write code in C.
Then what’s the point of adding any new features?
Some people want to use them, they are useful in some contexts and they often already exist in some form elsewhere, but the majority of people often do not need them.
That said, when you learn a foreign language, you do not learn every word in the dictionary and every grammatical structure. The same is true for programming. You just don't need to have a more up to date book than one on C89 to begin learning C.
A long time ago, Victor Yodaiken told me the best way to learn C was the old, K&R book. The explanations, examples, and even pitfalls were all explained well. My code worked without much fuss. That's probably because C hasn't changed much.
I ended up switching to Python for job requirements after getting through half the book. If I re-learn C, I'll go back to it. If it were C++, that would be a totally, different story since they kept piling features on over time.
Oh my... Are you serious? I'm almost triggered by this. A book about algorithms or data structures from 20 years ago has nothing more to teach? 3D game engine design from 20 years ago has nothing more to teach? No point in looking at the source code of Quake, reading k&r, and Knuth's TAOCP Volume 1 was published in 1968 so it's obviously irrelevant garbage!
I could spurr into an essay of what kind of lack of understanding you just portrayed about the world, but I won't.... I won't...
We’re talking about C/C++, not algorithms or data structures.
How you implement algorithms and data structures in C++/rust is semantics at best. The imperative shell of those languages are identical semantically right down to the memory model.
Right, that's why a 20 year old book on algorithms and data structures is not necessarily outdated, but a 20 year old book on C/C++ most certainly is.
My copy of The C++ Programming Language for C++98 is still useful today, as is copy of The C Programming Language for C89. The idea that these books are no longer useful is absurd. Modern compilers still support those versions and the new versions are largely extensions of the old (although C++11 changed some standard library definitions). The only way you could think this is if you have zero knowledge of these languages.
> The only way you could think this is if you have zero knowledge of these languages.
Exactly. For context see my original comment above about C/C++ books being paid.
Are you unable to use search engines:
https://www.learn-c.org/
There are so many free learning resources for these languages that it is ridiculous to say that you need books to learn them. The books are great, but non-essential. If you insist on reading books, there is an ancient invention called a library that you can use for free.
What C standard does that website describe?
At a glance, the code is compatible with all C standards ever published. You are too fixated on learning the latest. The latest is largely just a superset of the earlier standards and the new features are often obscure things you are unlikely to need or want to use.
The main exceptions that you actually would want to use would be the ability to declare variables anywhere in a block and use single line // comments from C++ in C99. Most C programmers do not even know about most of the things added in newer C standards beyond those and perhaps a handful of others.
I did more research and found https://isocpp.org/get-started which appears to be the authority for C++. It states that I will need a textbook for learning C++ and includes a link to Bjarne Stroustrup "Tour of C++" Amazon page (not buying it lol). For C the situation is more complicated because there appears to be multiple organizations making standards for it, and you have to pay "CHF 221.00" to even see the standard. It kind of reminds me of the web where there is also multiple consortiums making standards and browsers hopefully implement them (except the web standards are free). In conclusion I much prefer Rust where you can just read the docs without bullshit.
Almost nobody using C (or C++ for that matter) has read the standard. The standard exists for compiler developers. If you want to read the standard, you can get copies of the drafts for free. It is an open secret that the final draft is basically verbatim with the standard that costs money. However, it is very rare that a C programmer needs to read the standard.
As for C++, there is nothing at that link that says you need a textbook to learn C++ (and the idea that you need one is ludicrous). The textbooks are suggested resources. There are plenty of free resources available online that are just as good for learning C++.
You would be better off learning C before learning C++. C++ is a huge language and its common history with C means that if you do not understand C, you are likely going to be lost with C++. If you insist on learning C++ first, here is the first search result from DuckDuckGo when I search for "learn C++":
https://www.learncpp.com/
You will likely find many more.
For what it is worth, when I was young and wanted to learn C++, I had someone else tell me to learn C first. I had not intended to follow his advice, but I decided to learn C++ by taking a university class on the subject and the CS department had wisely made learning C a prerequisite for learning C++. I later learned that they had been right to do that.
After learning C++, I went through a phase where I thought C++ was the best thing ever (much like how you treat Rust). I have since changed my mind. C is far better than C++ (less is more). I am immensely proud of the C code that I have written during my life while I profoundly regret most of the C++ code that I have written. A particular startup company that I helped get off the ground after college runs their infrastructure on top of a daemon that I wrote in C++. Development of that daemon had been a disaster, with C++ features making it much harder to develop than it actually needed to be. This had been compounded by my "use all of the features" mentality, when in reality, what the software needed was a subset of features and using more language features just because I could was a mistake.
I had only been with the startup for a short time, but rejoined them as a consultant a few years ago. When I did, I saw that some fairly fundamental bugs in how operating system features were used from early development had gone unresolved for years. So much of development had been spent fighting the compiler to use various exotic language features correctly that actual bugs that were not the language's fault had gone unnoticed.
My successor had noticed that there were bugs when things had gone wrong, but put band-aids in place instead of properly fixing the bugs. For example, he used a cron job to restart the daemon at midnight instead of adding a missing `freeaddrinfo()` call and calling `accept()` until EAGAIN is received before blocking in `sigwaitinfo()`. Apparently, ~3000 lines of C++ code, using nearly every feature my younger self had known C++ to have, were too complicated for others to debug.
One of the first things I did when I returned was write a few dozen patches fixing the issues (both real ones and cosmetic ones like compiler warnings). As far as we know, the daemon is now bug free. However, I deeply regret not writing it in C in the first place. Had I written it in C, I would have spent less time fighting with the language and more time identifying mistakes I made in how to do UNIX programming. Others would have been been more likely to understand it in order to do proper fixes for bugs that my younger self had missed too.
> As for C++, there is nothing at that link that says you need a textbook to learn C++.
Sorry, it says that in their FAQ[0]. It also says "Should I learn C before I learn C++?" "Don’t bother." and proceeds to advertise a Stroustrup book[1].
[0]: https://isocpp.org/wiki/faq/how-to-learn-cpp#start-learning
[1]: https://isocpp.org/wiki/faq/how-to-learn-cpp#learning-c-not-...
> If you insist on learning C++ first, here is the first search result from DuckDuckGo when I search for "learn C++":
I don't insist on learning C++ and I even agree with you that C is better. But I have a problem with learning from non-authoritative sources, especially random websites and YouTube tutorials. I like to learn from official documentation. For C there appears to be no official documentation, and my intution tells me that, as nickpsecurity mentioned, the best way is to read the K&R book. But that brings us back to my original point that you have to buy a book.
> was the one true way (like you seem to have been with Rust)
I don't think there exists any one true way. It depends on what you do. For example I like Rust but I never really use it. I pretty much only use TypeScript.
> was the best thing ever (much like how you treat Rust)
I would actually prefer Zig over Rust but the former lacks a mature ecosystem.
> For example, they used a cron job to restart the daemon at midnight instead of adding a missing `freeaddrinfo()` call and calling `accept()` until EAGAIN is received before blocking in `sigwaitinfo()`.
This sounds like a kind of bug that would never happen in Rust because a library would handle that for you. You should be able to just use a networking library in C as well but for some reason C/C++ developers like to go as far as even implementing HTTP themselves.
> After learning C++...
Thanks for sharing your story. It's wholesome and I enjoyed reading.
> Sorry, it says that in their FAQ[0]. It also says "Should I learn C before I learn C++?" "Don’t bother." and proceeds to advertise a Stroustrup book[1].
They also would say "Don't bother" about using any other language. If you listen to them, you would never touch Rust or anything else.
> But I have a problem with learning from non-authoritative sources, especially random websites and YouTube tutorials. I like to learn from official documentation. For C there appears to be no official documentation, and my intution tells me that, as nickpsecurity mentioned, the best way is to read the K&R book. But that brings us back to my original point that you have to buy a book.
The K&R book is a great resource, although I learned C by taking a class where the textbook was "A Book On C". I later read the K&R book, although I found "A Book on C" to be quite good. My vague recollection (without pulling out my copies to review them) is that A Book On C was more instructional while the K&R book was more of a technical reference. If you do a search for "The C programming language", you might find a PDF of it on a famous archival website. Note that the K&R book refers to "The C programming language" by Kerninghan and Ritchie.
Relying on "authoritative" sources by only learning from the language authors is limiting, since they are not going to tell you the problems that the language has that everyone else who has used the language has encountered. It is better to learn programming languages from the community, who will give you a range of opinions and avoid presenting a distorted view of things.
There are different kinds of authoritative sources. The language authors are one, compiler authors are another (although this group does not teach), engineers who actually have used the language to develop production software (such as myself) would be a third and educational institutions would be a fourth. If you are curious about my background, I am ths ryao listed here:
https://github.com/openzfs/zfs/graphs/contributors
You could go to edx.org and audit courses from world renowned institutions for free. I will do you a favor by looking through what they have and making some recommendations. For C, there really is only 1 option on edX, which is from Dartmouth. Dartmouth is a world renowned university, so it should be an excellent teacher as far as learning C is concerned. They appear to have broken a two semester sequence into 7 online courses (lucky you, I only got 1 semester at my university; there was another class on advanced UNIX programming in C, but they did not offer it the entire time I was in college). Here is what you want to take to learn C:
https://www.edx.org/learn/c-programming/dartmouth-college-c-...
https://www.edx.org/learn/c-programming/dartmouth-college-c-...
https://www.edx.org/learn/c-programming/dartmouth-college-c-...
https://www.edx.org/learn/c-programming/dartmouth-college-c-...
https://www.edx.org/learn/c-programming/dartmouth-college-c-...
https://www.edx.org/learn/linux/dartmouth-college-linux-basi...
https://www.edx.org/learn/c-programming/dartmouth-college-c-...
There is technically a certificate you can get for completing all of this if you pay, but if you just want to learn without getting anything to show for it, you can audit the courses for free.
As for C++, there are two main options on edX. One is IBM and the other is Codio. IBM is a well known titan of industry, although I had no idea that they had an education arm. On the other hand, I have never heard of Codio. Here is the IBM sequence (note that the ++ part of C++ is omitted from the URLs):
https://www.edx.org/learn/c-programming/ibm-fundamentals-of-...
https://www.edx.org/learn/object-oriented-programming/ibm-ob...
https://www.edx.org/learn/data-structures/ibm-data-structure...
There actually are two more options on edX for C++, which are courses by Peking University and ProjectUniversity. Peking University is a world class university in China, but they only offer 1 course on edx that is 4 weeks long, so I doubt you would learn very much from it. On the other hand, I have never heard of ProjectUniversity, and their sole course on C++ is only 8 weeks long, which is not very long either. The 3 IBM courses together are 5 months long, which is what you really want.
> I pretty much only use TypeScript.
Learn C, POSIX shell scripting (or bash) and 1 functional programming language (Haskell is a popular choice). You will probably never use the functional programming language, but knowing about functional programming concepts will make you a better programmer.
> This sounds like a kind of bug that would never happen in Rust because a library would handle that for you. You should be able to just use a networking library in C as well but for some reason C/C++ developers like to go as far as even implementing HTTP themselves.
First, I was using a networking library. The C standard library on POSIX platforms is a networking library thanks to its inclusion of the Berkeley sockets API. Second, mistakes are easy to criticize in hindsight with "just use a library", but in reality, even if you use a library, you could still make a mistake, just as I did here. This code also did much more than what my description of the bug suggested. The reason for using asynchronous I/O is to be able to respond to events other than just network I/O, such as SIGUSR1. Had I not been doing that, it would not have had that bug, but it needed to respond to other things than just I/O on a socket.
I described the general idea to Grok and it produced a beautiful implementation of this in Rust using the tokio "crate". The result had the same bug that the C++ code had, because it made the understandable assumption my younger self made that 1 SIGIO = 1 connection, but that is wrong. If two connection attempts are made simultaneously from the perspective of the software, you only get 1 SIGIO. Thus, you need to call accept() repeatedly to drain the backlog before returning to listening for signals.
This logical error is not something even a wrapper library would prevent, although a wrapper library might have prevented the memory leak, but what library would I have used? Any library that wraps this would be a very thin wrapper and the use of an additional dependency that might not be usable on then future systems is a problem in itself. Qt has had two major version changes since I wrote this code. If I had used Qt 4's network library, this could have had to be rewritten twice in order to continue running on future systems. This code has been deployed on multiple systems since 2011 and it has never once needed a rewrite to work on a new system.
Finally, it is far more natural for C developers and C++ developers to use a binary format over network sockets (like I did) than HTTP. Libcurl is available when people need to use HTTP (and a wide variety of other protocols). Interestingly, an early version of my code had used libcurl for sending emails, but it was removed by my successor in favor of telling a PHP script to send the emails over a network socket (using a binary format).
> Thus, you need to call accept() repeatedly to drain the backlog before returning to listening for signals.
It's not just accept. If your socket is non-blocking the same applies to read, write, and everything else. You keep syscalling until it returns EAGAIN.
> I described the general idea to Grok and it produced a beautiful implementation of this in Rust using the tokio "crate". The result had the same bug that the C++ code had, because it made the understandable assumption my younger self made that 1 SIGIO = 1 connection, but that is wrong.
I don't know what your general idea was but tokio uses epoll under the hood (correctly), so what you are describing could only have happened if you specifically instructed grok to use SIGIO.
> Finally, it is far more natural for C developers and C++ developers to use a binary format over network sockets (like I did) than HTTP.
Designing a custom protocol is way more work than just using HTTP. <insert reasons why http + json is so popular (everyone is familiar with it blah blah blah)>.
> It's not just accept. If your socket is non-blocking the same applies to read, write, and everything else. You keep syscalling until it returns EAGAIN.
You do not call read/write on a socket that is listening for connections.
> I don't know what your general idea was but tokio uses epoll under the hood (correctly), so what you are describing could only have happened if you specifically instructed grok to use SIGIO.
That is correct. There is no other way to handle SIGUSR1 in a sane way if you are not using SIGIO. At least, there was no other way until signalfd was invented, but that is not cross platform. epoll isn't either.
> Designing a custom protocol is way more work than just using HTTP. <insert reasons why http + json is so popular (everyone is familiar with it blah blah blah)>.
You are wrong about that. The code is just sending packed structures back and forth. HTTP would overcomplicate this, since you would need to implement code to go from binary to ASCII and ASCII to binary on both ends, while just sending the packed structures avoids that entirely. The only special handling this needs is to have functions that translate the structures from host byte order into network byte order and back, to ensure that endianness is not an issue should there ever be an opposite endian machine at one end of the connection, but those were trivial to write.
Do yourself a favor and stop responding. You have no idea what you are saying and it is immensely evident to anyone who has a clue about software engineering.
> You are wrong about that. The code is just sending packed structures back and forth.
Among other things, this would only work if your client is written in a language that supports C structures.
> Do yourself a favor and stop responding. You have no idea what you are saying and it is immensely evident to anyone who has a clue about software engineering.
Says the one who didn't know how to use non-blocking sockets.
> That is correct. There is no other way to handle SIGUSR1 in a sane way if you are not using SIGIO. At least, there was no other way until signalfd was invented, but that is not cross platform. epoll isn't either.
```
use std::io;
use tokio::{
};#[tokio::main(flavor = "current_thread")]
async fn main() -> io::Result<()> {
}```
> Among other things, this would only work if your client is written in a language that supports C structures.
Such languages are used at both ends. Otherwise, this would not have been working in production for ~13 years.
> Says the one who didn't know how to use non-blocking sockets.
Neither did you until you learned it. If you successfully begin a career in software engineering and years later, have the humility to admit the mistakes you made when starting out for the benefit of others, you will deserve to have an incompetent know it all deride you for having been so kind to admit them, just like you are doing to me here.
Anyone with a modicum of programming knowledge can write code snippets free from mistakes immediately after being told about the mistakes that would be made when given a simplified explanation of one thing that is done in production software. The problem with software engineering is that nobody tells you everything you can do wrong before you do it, and you are not writing code snippets, but production software.
> If you successfully begin a career in software engineering and years later, have the humility to admit the mistakes you made when starting out for the benefit of others, you will deserve to have an incompetent know it all deride you for having been so kind to admit them, just like you are doing to me here.
I wouldn't "deride" you if you weren't acting arrogant and calling me incompetent or whatever.
> The problem with software engineering is that nobody tells you everything you can do wrong before you do it
Maybe, but the docs definitely tell you about EAGAIN and freeing memory after you're done using it. In Rust many kinds of logical errors you could potentially have made are eliminated by the type system though. For example I wrote a news scraper in Rust and ran it locally a couple times to see that it works, and it's been running for half a year now on a VPS and I never had to touch it or restart anything.
> You could go to edx.org and audit courses...
This is great advice, thanks!
> edit2: networking, signal processing, automotive, learning about industry protocols and devices of any sort...
I admit there is many great products that are written in C that aren’t going anywhere any time soon, notably SQLite, but there is no reason to write new software in C or C++.
I wrote a new daemon in C the other day. Plenty of people will continue to write software in C. Some will even write it in C++. There is nothing you can write that will convince the world to stop writing software in these languages. We went through this once with Java. We are going through it with Rust. We will go through it with Zig or whatever it is that people say everyone should adopt next instead of Rust and all else that came before it.
There's tools that can prove the absence of runtime errors in industrially-useful subsets of C. Frama-C, RV-Match, and Meta's Infer come to mind. That code is then usable in about anything because so much of it is written in or can call C. Until Rust has that combo, there's still a reason to use C.
Personally, I'd use both Rust and C with equivalent code. The Rust types and borrow checker give some extra assurance that C might not have. The C tooling gives extra assurance Rust doesn't have. Win, win. If I want, I can also do a certified compile or cross-compile of the Rust-equivalent, C code.
Astree claims to be able to prove the absence of runtime errors in both C and C++, without requiring the use of subsets:
https://www.absint.com/astree/index.htm
By the way, C has a formally verified C compiler:
https://compcert.org/compcert-C.html
Yeah, CompCert will certify a binary for those willing to buy it or use a GPL license. Empirical testing showed it had no bugs in its middle end, unlike other compiler.
On Astree, I couldn't believe it supported all language constructs. I found this on your link:
"and is subject to the same restrictions as Astrée for C.
The high-level abstraction features and template library of C++ facilitate the design of very complex and dynamic software. Extensive use of these features may violate the established principles of safety-critical embedded software development and lead to unsatisfactory analysis times and results. The Astrée manual gives recommendations on the use of C++ features to ensure that the code can be well analyzed. For less constrained (less critical) C++ code, we recommend using the standalone RuleChecker."
So, it still does require a language subset that reduces complexity to benefit from the full analysis. They have greatly expanded what errors they catch since I first read about them. So, thanks for the link.
I researched and discovered kani https://github.com/model-checking/kani, it's pretty cool.
```rust
#[kani::proof]
fn main() {
} ```I do, and will, the industry does and will, for at least a few more decades. And I even enjoy doing so (with C; C++ is more forced upon me, but that'll be the case for some time to come)
That’s what I’m saying. By a few decades you and most of those alleged 7 million C/C++ developers will retire and there won’t be anyone to replace them because everyone will be using Rust or Zig or Go.
Very strong statement, one I don't really believe
That’s what happened to COBOL, right?
In COBOL’s case, nobody really wanted to write software in it in the first place. People used assembly or FORTRAN at the time. MBAs wanted a language corporate secretaries could use, so they made COBOL. It failed at its main purpose, but since IBM pushed it for business processing, people were coerced into writing software with it since if they did not use it, they would not have a job. As the industry developed, they stopped finding new people that they could coerce into using it and the old people started retiring/dying. Unlike COBOL adoption, C and C++ adoption occurred because software engineers wanted to use them due to merit.
> anything from embedded on the weirdest platforms, basic parsing, writing compilers, language design, high performance computing, teaching of algorithms, data structures, distributed systems, whatever
All that is language-agnostic and doesn’t necessarily have anything to do with C.
Yes, but there is material covering all of those aspects with implementations in C plus libraries plus ecosystem support! From teaching material to real world reference implementations to look at and modify and learn from.
And C maps so directly to so many concepts; it's easy to pick up any of those topics with C; and it being so loose makes it even perfect to explore many of those areas to begin with, since very quickly you're not fighting the language to let you do things.
People may learn from material that uses C for illustration purposes, but that won’t prompt them to write their own C. And don’t even mention ecosystem support in C/C++ where developers are notorious for reimplementing everything on their own because there is no package manager.
"rust import csv-parser" "you've installed 89 packages"
why is my executable 20 mb, not as performant as a 50 kb C file & doesn't build a year later if I try to build with 89 new versions of those packages
obligatory xkcd reference: https://imgs.xkcd.com/comics/dependency_2x.png this is what package managers lead to
Conversely, "why does my hand-written CSV parser only support one of the 423 known variants of CSV, and it isn't the one our customer sent us yesterday?"
You kind of have a point behind dependency hell, but the flip side is that one needn't become an expert on universal CSV parsing just to have a prayer of opening them successfully.
You are greatly exaggerating the numbers, and Rust and its ecosystem are known for being stable. Are you saying everyone should write their own csv parser? Also it’s highly likely that an existing CSV library would be optimized, unlike whatever you wrote ad-hoc, so your performance argument doesn’t hold.
I'm saying package managers automate dependency hell and software is and will be less stable & more bloated as a consequence. And one should know how to write a csv parser and yes, even consider writing one if there are obvious custom restraints and it's an important part of one's project.
(and yes, numbers were exaggerated; I picked something trivial like a csv parser pulling in 89 packages for effect; the underlying principle sadly holds true)
Anyone can read a file, split it by newline and split it by comma, but what if values contain newlines or commas? How do you unescape? What about other edge cases? In Rust an existing library would handle all that, and you would also get structure mapping, type coercion, validation etc for free.
The number of dependencies does not indicate how bloated your app is. Package managers actually reduce bloat because your dependencies can have shared dependencies. The reason C programs may seem lightweight is because their number of dependencies is low, but each dependency is actually super fat, and they tend to link dynamically.
In the context of Rust it is not about "bloat" indeed. The compiler includes only used bits and nothing more. However, there are other problems, like the software supply chain security. More dependencies you have, more projects you have to track. Was there a vulnerability that affects me? Is project unmaintained and some ill factor took it over?
In C this was actually a less problem since you had to copy-paste the shared code into your program and at some level you were manually reviewing it all the time.
Also in Rust people tend to write very small libraries and that increases the number of dependencies. However, many still not follow SemVer et. al and packages tend to be unstable too. On top of additional security issues. They maybe be useful for a short time but in many cases you might need to think the lifetime of your application up to 10 years.
> However, there are other problems, like the software supply chain security.
It's not a problem with Rust specifically though. It's not unique to Rust.
> Also in Rust people tend to write very small libraries and that increases the number of dependencies. However, many still not follow SemVer et. al and packages tend to be unstable too.
Don't use random unpopular crates maintained by unknown people without reviewing the code.
That applies to your distro package manager too.
Probably not. Many people prefer C/C++ to Rust, which has its own fair share of problems.
Two people is many people. The general trend I see is that Rust is exploding in adoption.
The last I checked various stats (GitHub Language stats, TIOBE, etc.), Rust wasn't even in the top 10. I'm sure its adoption is increasing. However, other languages like Go seem to be doing much better. Neither will replace C++ or C anytime soon.
C/C++ will be replaced incrementally and it’s already happening. Cloudflare recently replaced nginx with their own alternative written in Rust for example.
That's nice, but a couple of Rust rewrites are not proof of a general trend.
I've been working with C for over 30 years, both professionally and a hobbyist. I have experimented with Rust but not done anything professionally with it. My gut feel is Rust is too syntactically and conceptually complex to be a practical C replacement. C++ is also has language complexity issues, however it can be adopted piecemeal and applied to most existing C code.
> My gut feel is Rust is too syntactically and conceptually complex to be a practical C replacement.
That would depend on what you use C for. But I sure can imagine people complain that Rust gets in the way of their prototyping while their C code is filled with UB and friends.
> That's nice, but a couple of Rust rewrites are not proof of a general trend.
It’s not just a couple. We’ve seen virtually all JS tooling migrate to Rust, and there is many more things but I can’t remember by name.
It is, but it is still tiny compared to C/C++. And many people also do not like it.
There are two categories of people who don’t like Rust:
1. C/C++ developers who are used to C/C++ and don’t want to learn Rust.
2. Go developers who claim Rust is too difficult and unreadable.
Which one is you?
I think the "don't want to learn" is a very poor argument. I learn stuff every day, but I want want to decide myself what I learn to solve my problems, not because Rust folks think everybody has to learn Rust now. I learned a bit of Rust out of curiosity, but not so much I could do a lot with it. I do not want to learn more, because I think the language has severe flaws and and much less suitable than C for my use cases.
I know a guy who used to love Rust and his cannot stand it. The hype wore off in his case.
Does he prefer fighting libtool, make, cmake, configure, automake, autoconf and autoreconf just to add a couple libraries into his project? When I tried to use C, I wrote 10 lines of code and spent hours trying to make all that shit work. It makes me laugh when people say Rust is complicated.
It really is not that complicated. You just use -llibrary when linking and it links.
Oh I never realized I was supposed to install -dev packages, I thought I had to compile myself.
Whether you need -dev packages (for headers) depends on your operating system. I run Gentoo. All headers are always on the system. Other distributions ship the headers separately in -dev packages to save space and you need to install them. You likely can install all -dev packages for everything on your system so you do not need to get the individual ones.
Autocorrect seems to have made a typo worse here. It was supposed to be now, not his.
I think we will get the same safety benefits of Rust in a version of C relatively soon.
Borrow checker is not the only feature that makes Rust great though.
Yes, it also has many aspects I do not like about it. Let's not pretend everybody shares your enthusiasm for it.
What aspects do you not like about Rust?
Too much complexity, long build times, monomorphization, lack of stability / no standard, poor portability, supply chain issues, no dynamic linking, no proper standard, not enough different implementations, etc. It is a nice language though, but I do not prefer it over C.
> long build times, monomorphization
Monomorphization is what causes long build times, but it brings better performance than dynamic dispatch.
> lack of stability
There was another comment which also never elaborated on how Rust is not stable.
> supply chain issues
Not a language issue, you choose your dependencies.
> no proper standard, not enough different implementations
Is that a practical problem?
> no dynamic linking
There is.
If your like Rust, this is fine, but I will stay with C. I find it much better for my purposes.
He said elsewhere that he does not even use Rust. He uses typescript. I am confused why he is bothering to push Rust when he does not even use it.
I would use it if I had the opportunity, that's why.
> > no dynamic linking
> There is.
Eh, I'm a Rust fan, and I hate the dynamic linking situation too.
I genuinely cannot see how Rust would be able to scale to something usable for all system applications the way it is now. Is every graphical application supposed to duplicate and statically link the entire set of GNOME/GTK or KDE/Qt libraries it needs? The system would become ginormous.
The only shared library support we have now is either using the C ABI, which would make for a horrible way to use Rust dependencies, or by pinning an exact version of the Rust compiler, which makes developing for the system almost impossible.
Hopefully we'll get something with #[export] [1] and extern "crabi" [2], but until then Rust won't be able to replace many things C and C++ are used for.
[1] https://github.com/rust-lang/rfcs/pull/3435
[2] https://github.com/rust-lang/rfcs/pull/3470
> I genuinely cannot see how Rust would be able to scale to something usable for all system applications the way it is now. Is every graphical application supposed to duplicate and statically link the entire set of GNOME/GTK or KDE/Qt libraries it needs? The system would become ginormous.
You don't have to statically link C libraries.
I am referring to Rust scaling up to where C is now (i.e. try to remove C from the picture).
As in, if there will ever be a Rust equivalent of KDE/GNOME (e.g. maybe COSMIC), it will have similar libraries. They will have to be in Rust, and will have to be statically linked. And they will eventually grow up to be the size of KDE/GNOME (as opposed to the tiny thing COSMIC is now).
If it is any consolation, early C did not have dynamic linking either. It was added afterward. From what I understand, UNIX systems had statically linked binaries in /bin until ELF was introduced and gradually switched to dynamically linked binaries afterward.
To generate safer C?
Compiling Rust to C doesn’t simplify interoperability. Either way you’ll be calling C functions. I assume compiling Rust to C is useful if you’re targeting some esoteric platform that Rust compiler doesn’t support.
Nim to C compiler, 100% test pass rate.
Is it LLVM IR --> C? Or Rust AST to C?
Found the answer in the project readme.
> My representation of .NETs IR maps nicely to C, which means that I was able to add support for compiling Rust to C in 2-3K LOC. Almost all of the codebase is reused, with the C and .NET specific code only present in the very last stage of compilation
Which might also allow one to use tools that work on .NET bytecode. They include verification, optimization, debugging, and other transpilers. You might also get a grant or job offer from MS Research. :)
It is a rustc backend, ie an alternative to llvm, gcc, or the cranelift backends.
It started as a .NET backend but they found that their approach could easily support C code generation as well so they added that. They do this by turning what rustc gives them into their own IR.
But does it carry the Rusty guarantees?
If the transpilation itself is bug-free, why not? For static guarantees, provided we transpile Rust code that already compiles on a normal Rust compiler, the guarantees are already checked and there, and the dynamic ones such as bounds checking can be implemented runtime in C with no problems.
this assumes the rusty guarantees are transitive. There's no reason to believe it isn't, but it'd be nice to see some sort of proof, or at least an argument for it.
Should be. The rust borrow checker has no runtime component. It checks the code as-is before (or during) compilation.
Arguably it’s not the compiled binary that’s “safe”. It’s the code.
Borrow checker, and more generally any type checkers, are essentially terminating programs ran during compilation process, thus safety guarantees given by them are ensured before the code is transformed into some target language.
Thats assuming lossless transpilation though
If you mean 'no bugs in compiler' then yes. The safety of the target language doesn't matter: the output C is has an equivalent role to output machine code, those languages themselves are as unsafe as they can get, it's just that compilers output is a safer subsection of 'all programs which can be expressed in them'.
That's a problem for almost every language, not just Rust. C++ also compiles to intermediate representations, and then to machine code. Errors happen on that path. Rust just get rid of a lot of errors that could have been in the original specification (the source code).
Rust does not generate machine code itself. It uses LLVM to do that and there is no proof that the transformations done by that continue to keep the borrow checker guarantees. One just assumes with sufficient testing all bugs will be discovered.
Then the machine code generated by LLVM is not run directly by modern CPUs and is translated into internal representation first. And the future CPUs will behave like JIT-compilers with even more complex transformations.
The intermediate C code generated by this project just adds yet another transformation not fundamentally different from any of the above.
Rust does not guarantee that all bounds checks can be proven correct at compile time, so it relies on runtime bounds checks. If this does not implement the same bounds checks, then probably not.
Why wouldn't it?
It could fail if the generated C code triggered Undefined Behavior.
For example, signed overflow is UB in C, but defined in Rust. Generated code can't simply use the + operator.
C has type-based alias analysis that makes some type casts illegal. Rust handles alias analysis through borrowing, so it's more forgiving about type casts.
Rust has an UnsafeCell wrapper type for hacks that break the safe memory model and would be UB otherwise. C doesn't have such thing, so only uses of UnsafeCell that are already allowed by C are safe.
I have workarounds for all "simple" cases of UB in C(this is partially what the talk is about). The test code is running with `-fsantize=undefined`, and triggers no UB checks.
There are also escape hatches for strict aliasing in the C standard - mainly using memcpy for all memory operations.
> It could fail if the generated C code triggered Undefined Behavior.
> For example, signed overflow is UB in C, but defined in Rust. Generated code can't simply use the + operator.
Obviously, yes, but it could generate overflow checks.
Wait until you find out how unsafe software written in the machine language that Rust usually transpiles to is.
That's not the same, and not what pornel is talking about. The x86 ADD instruction has a well-defined behavior on overflow, and i32 + i32 in Rust will usually be translated to an ADD instruction, same as int + int in C. But a C compiler is allowed to assume that a signed addition operation will never overflow (the dreaded Undefined Behavior), while a Rust compiler must not make that assumption. This means that i32 + i32 must not be translated to int + int.
For example, a C compiler is allowed to optimize the expression a+1<a to false (if a is signed), but a Rust compiler isn't allowed to do this.
Very cool. C to Rust would be fantastic.
> C to Rust would be fantastic.
This would have to go into one big unsafe block for any nontrivial program. C doesn’t convey all of the explicit things you need to know about the code to make it even compile in Rust.
I once implemented a WASM to Rust compiler that due to WASM's safety compiles to fully safe Rust. So I was able to compile C -> WASM -> Rust and ended up with fully safe code. Though of course, just like in WASM, the C code is still able to corrupt its own linear memory, just can't escape the "sandbox". Firefox has employed a similar strategy: https://hacks.mozilla.org/2020/02/securing-firefox-with-weba...
I'd love to check that out. Did it unroll a wasm interpreter into wasm_op function calls?
There's no interpreter, I just map each instruction to equivalent Rust code. Linear memory is accessed through a trait.
The compiler is here: https://github.com/CryZe/wasm-to-rust
I have an example of a GameBoy emulator compiled from AssemblyScript to WASM to Rust here: https://github.com/CryZe/wasmboy-rs/blob/master/src/wasm.rs
That is super cool!
Have you run into any limitations?
Have you tried running in loop, wasm->rust->wasm->rust ?
This is not-unlike unrolling an interpreter. There was a lua2c project that did something similar.
If your translator is correct, the rust front end enforces the semantics of rust then C implements them. It's as safe as any other implementation.
If that feels uncomfortable, consider that x64 machine code has no approximation to rust safety checks, and you trust rust binaries running on x64.
"Correct" is doing some heavy lifting here but generally people seem willing to believe that their toolchain is bug free.
They are discussing C to Rust, not the topic of the post. Rust would need to guess the semantics of the original C.
Mark Russinovich recently gave a talk at a UK Rust conference that mentioned Microsoft's internal attempts at large scale C->Rust translation, https://www.youtube.com/watch?v=1VgptLwP588
Note the AI part of the tooling.
Tools like those exist. The problem with them is that they use unsafe blocks a lot, and the code usually isn't very idiomatic. Translating global variable state machines into more idiomatic Rust state machines based on things like named enums, for instance, would be very difficult.
With the help of powerful enough AI we might be able to get a tool like this, but as AI still very much sucks at actually doing what it's supposed to do, I don't think we're quite ready yet. I imagine you'd also need enough memory to keep the entire C and Rust code base inside of your context window, which would quickly require very expensive hardware once your code grows beyond a certain threshold. If you don't, you end up like many code assisting LLMs, generating code independently that's incompatible with itself.
Still, if you're looking to take a C project and extend it in Rust, or perhaps slowly rewrite it piece by piece, https://c2rust.com/ is ready for action.
See https://github.com/immunant/c2rust
What benefit would you envision from this?
There is DARPA program called TRACTOR to pursue this:
https://www.darpa.mil/news/2024/memory-safety-vulnerabilitie...
1. It means you don't need C code & a C compiler in your project any more, which simplifies infrastructure. E.g. cross compiling is easier without any C.
2. You can do LTO between Rust and the C->Rust code so in theory you could get a smaller & faster executable.
3. In most cases it is the first step to a gradual rewrite in idiomatic Rust.
Rust to C? Why would someone do that. Just write C.. if you can figure rust out you surely can figure C out and be proficient.
Because of the niceties of Rust, combined with the widespread compatibility and architecture support of gcc / C compilers in general?
Rust is a modern language, with package management, streamlined integrated build/testing tools, much less cruft, and lots of high-level features and syntax that people actually like. C is neat but complex codebases benefit from modern languages that help in building robust abstractions while still maintaining the speed of C. Not to mention, of course, the borrow checker and memory safety.
So you can get the benefits of Rust on platforms that rustc doesn't support. Seems pretty straightforward.
It seems like there's a healthy dose of "because it can be done" in play here, but also because there are a lot of platforms that are not supported by Rust where a Rust-to-C converter that generated standard-enough code could be used to bridge the gap.
I will read further into the project just off the bat I don’t get the point. Good luck it looks quite extensive :)
At first I read it as C to rust compiler.
What is the point of compiling rust to C?
I think there are probably C compilers for more platforms than there are rust compilers. So, if you want to compile your rust project on some obscure platform that doesn’t have a rust compiler for it yet, you could compile to C and then compile the resulting C code for that platform?
Just a guess.
This project doesn’t have that as a goal. In fact, it doesn’t even have “Rust to C compiler” as a goal. https://github.com/FractalFir/rustc_codegen_clr:
“ The project aims to provide a way to easily use Rust libraries in .NET. It comes with a Rust/.NET interop layer, which allows you to easily interact with .NET code from Rust
[…]
While .NET is the main focus of my work, this project can also be used to compile Rust to C, by setting the C_MODE enviroment flag to 1.
This may seem like a strange and unrelated feature, but the project was written in such a way that this is not only possible, but relatively easy.”
It also doesn’t mention for which version of C it produces code. That may or may not hinder attempts to use this to run rust on obscure platforms.
The README is slightly out of date, sorry. Supporting old platforms is one of the goals.
Truth be told, the support for C was at first added as a proff-of-concept that a Rust to C compiler is possible. But it worked surprisingly well, so I just decided to roll with it, and see where it takes me.
My policy in regards to C version is: I want to be as close to ANSI C as possible. So, I avoid modern C features as much as I can. I don't know if full compatibility is achievable, but I certainly hope so. Only time will tell.
Some simpler pieces of Rust work just fine with ANSI C compilers, but more complex code breaks(eg. due to unsupported intrinsics). If I will be able to solve that(+ some potential soundness issues) then I'll be able to use ANSI C.
The article mentions ANSI-C at places. So seems like the old c standard is targeted.
This is a fairly common technique in compiler construction and programming language research: Don't try to emit some machine code, instead emit C or an IR for clang or GCC. And suddenly your little research language (not that rust is one) is executable on many, many platforms, can rely on optimizations the compilers can do, has potential access to debug handling, ..
Vala [1] is, perhaps, the most prominent example of practically used programming language with such compiler.
[1] https://en.wikipedia.org/wiki/Vala_(programming_language)
Regarding the other way, I guess a lot of (practically) legal C wouldn't compile to Rust at all due to the language's restrictions and C's laxness, while I think all Rust could be translated to C.
Exactly. Btw rust toolchain is quite complicated while a code that was tanspiled to C might be as well compiled to e.g. 6052
Using C compiler infrastructure, taking Rust where rustc/llvm does not go. Proprietary platforms with proprietary compilers for example.
> What is the point of compiling rust to C?
To address platforms that don't support Rust. TFA mentions NonStop, whatever it is.
Fault-Tolerant mainframe type systems.
https://en.m.wikipedia.org/wiki/NonStop_(server_computers)
They are amazing machines designed for fault tolerance (99.999% reliability). The Wikipedia article below has design details for how many generations were made. HP bought them.
https://en.m.wikipedia.org/wiki/Tandem_Computers
I think it would be useful in open-source, fault tolerance to copy one of their designs with SiFive's RISC-V cores. They could use a 20 year old approach to dodge patent issues. Despite its age, the design would probably be competitive, maybe better, than FOSS clusters on modern hardware in fault tolerance.
One might also combine the architecture with one of the strong-consistency DR'S, like FoundationDB or CochroachDB, with modifications to take advantage of its custom hardware. At the local site, the result would be easy scaling of a system whose nodes appeared to never fail. The administrator still has to do regular maintenance, though, as the system reports component failures which it works around.
Not only does NonStop not support Rust, but apparently they failed to port gcc to it, even. So compiling Rust straight to C itself is pretty much the only option there.
I guess it's to target platforms (like some microcontrollers) which don't yet have a native Rust compiler, but often do have a C compiler?
To use rust in places where you can only use C. I imagine there are quite a few obscure microcontrollers that would benefit greatly from this pipeline.
Hell, you might finally be able to get Rust into the Linux kernel. Just don't tell them the code was originally written in Rust to calm their nerves.
Game consoles generally only offer clang as a possibility for compiler. If you can compile rust to C, then you can finally use rust for videogames that need to run everywhere.
Is Steam Deck a monopoly yet? I feel like if your game compiles to Linux, you can target pretty much every market out there.
I don’t think I’ve ever heard those two terms “video game” and “run everywhere” in the same sentence. Bravo.
Excellent.
Now we can quickly re-rustify projects by converting them to C.
If I see something like "At least on Linux, long and long long are both 64 bits in size." my skin starts to crawl. Not only that, but GCC defines __builtin_popcount() with unsigned int / long / long long, respective, i.e. even in the text it should be mentioned correctly (unless a different compiler uses signed types there ... ugh). The call is done with unsigned, using uint64_t as a type-cast, but using a fixed __builtin_popcountl() which translates to unsigned long. There are systems where this will fail, i.e. the only safe bet to use here is __builtin_popcountll() as this will cover at least 64 bit wide arguments.
Also, if a * b overflows within the result type, it is an undefined behavior according to the C standard, so this overflow check is at least not properly portable, either, and the shown code for that is actually buggy because the last A1 has to be A0.
No idea why all that gets me so grumpy today ...
Correct me if I am wrong C, unsigned overflow is well-defined - at least the GCC manual says so, but I'll have to check the standard.
https://www.gnu.org/software/c-intro-and-ref/manual/html_nod...
Since signed multiplication is bitwise-equivalent to unsigned multiplication, I use unsigned multiplication to emulate UB-free signed multiplication. The signed variant of this overflow check is a bit harder to read because of that, but it still works just fine.
bool i128_mul_ovf_check(__int128 A0 ,__int128 A1 ){
bb0:
if((A1) != (0)) goto bb1;
return false;
bb1:
return (((__int128)((__uint128_t)(A0) * (__uint128_t)(A1))) / (A1)) == (A1);
}
As for using `__builtin_popcountll` instead - you are right, my mistake. Thanks for pointing that out :).
I did not use the word "unsigned" before long long for the sake of readability - I know that repeating a word so many times can make it harder to parse for some folk. The project itself uses the correct types in the code, I was just kind of loose with the language in the article itself. My bad, I'll fix that and be a bit more accurate.
Once again, thanks for the feedback!
Yes, the C and C++ unsigned types are analogous to Rust's Wrapping<u8> Wrapping<u16> Wrapping<u32> and so on, except that their size isn't nailed down by the ISO document.
thank for PR. very fast turn around.
[dead]
Why would I use a tool that doesn't pass all tests?
The post is an update on the status of an ongoing project.
> This is an update on the progress I have made on my Rust to C compiler.
> There still are about 65 tests that need fixing, but they all seem to have pretty similar causes. So, fixing them should not be too difficult.
To not write C
Would it be possible for Rust to output LLVM IR? Would that make it easier to port if they have a LLVM frontend?
This comment is strange, given that LLVM is rust's most mature backend
I think the GP means emit LLVM IR directly. And the answer to that is yes; you can pass a flag to rustc that will emit the IR[1].
[1]: https://stackoverflow.com/questions/39004513/how-to-emit-llv...
This is what I meant, thank you.
Of course, everyone votes up the headlines, but this link seems like premature WIP. Hopefully this will get posted for real after the presentation.
This is Hacker News, not Product Hunt.
I clicked through to the project at https://github.com/FractalFir/rustc_codegen_clr - from a quick glance at it, with 1.8k stars and 17 contributors, it deserves a better treatment than a passive—aggressive dismissal like this as a top comment.
It is a very impressive piece of work.
Right, and that probably should have been the link rather than some in-process thoughts about popcount or w/e. Sorry for not figuring it out and clicking around effectively.
The linked article was mostly meant for people already lossely familiar with the project, but it seems it escaped its intended audience.
I do have a whole bunch of articles about the project on my website, going trough the entire journey of the project, from its start as a Rust to .NET compiler, to the current state.
https://fractalfir.github.io/generated_html/home.html
I should have probably linked the previous articles in this one - I'll add that to my website. I'll also look into adding some more context to the articles next time.
Thanks for the feedback :)
I guess the complaint was more about your fans updooting stuff, so apologies if it sounded like I was shitting on this. Cool project, and I really am awaiting the presentation/writeup.
Your positive attitude and the talent is inspiring. Thank you very much!
If you read the article you'll see this is a status report and not a pitch for a final product.
Yeah, exactly. Here on a website called 'Hacker News', we're only interested in projects when they're feature complete and mature enough for production deployment, not before. (/s)
I'm not convinced that it’s worth spending any time supporting most proprietary systems. Maybe not even Windows, but especially the really expensive ones.
You shouldn't spend your own effort; you should make it clear that you're open to users of such systems contributing.
That's how GCC became so dominant - there were people already using all sorts of Unixen and they wanted a compiler, so they made it work.
> You shouldn't spend your own effort; you should make it clear that you're open to users of such systems contributing.
In practice you can't really draw a line between those two things.
I don't know the end result, but I remember a discussion of how implementing parts of Git in Rust would be a problem because NonStop, a currently supported platform, has no Rust support. Of course the sane response would be "screw NonStop then", but having accepted contributions to make NonStop a supported platform that isn't an easy path to take.
That is absolutely true but exotic platforms are also fun to investigate and you can learn a lot. So I'd say you shouldn't spend your own effort if you don't want to but I am glad fractalfir did and I am looking forward to the his RustWeekNL presentation.
Of course, accepting contributions comes with some effort, too.
Funny, because the average person is convinced it's not worth spending any time supporting Linux!
I'm always convinced that people will pick up arbitrary projects that they are interested in and might not necessarily lead to a new pitch for venture capital or the next unicorn.
How is this not dangerous? How can one be assured that all of the compile-time safety features of the Rust compiler are still in effect? Handwaving does not help.
How does the rust compiler assure that when compiling to machine code? Machine code is less safe than C after all.
Machine code is generally much safer than C - e.g. it usually lacks undefined behaviour. If you're unsure about how a given piece of machine code behaves, it's usually sufficient to test it empirically.
Not true on RISC-V. That's full of undefined behaviour.
But anyway this is kind of off-topic. I think OutOfHere was imagining that this somehow skips the type checking and borrow checking steps which of course it doesn't.
What's all that undefined behavior? Closest I can think of is executing unsupported instructions, but you have to mess up pretty hard for that to happen, and you're not gonna get predictable behavior here anyway (and sane hardware will trap of course; and executing random memory as instructions is effectively UB on any architecture).
(there's a good bit of unpredictable behavior (RVV tail-agnostic elements, specific vsetvl result), but unpredictable behavior includes any multithreading in any architecture and even Rust (among other languages))
Accessing non-existent CSRs is another big one, which also means you can't probe for features.
There's loads more though. Just search for "reserved" in the ISA manual.
Of course a Rust to C compiler is not going to hit any of these. I was just pointing them out.
Fair point on CSRs, though I'd count that as a subset of unsupported/not-yet-specified instructions; pretty sure all of the "reserved"s in the spec are effectively not-yet-defined instructions too, which'll have equivalents in any architecture with encoding space left for future extensions, not at all unique to RISC-V.
But yeah, no try-running-potentially-unsupported-things-to-discover-what-is-supported; essentially a necessary property for an open ISA as there's nothing preventing a vendor from adding random custom garbage in encoding space they don't use.
Yeah I guess the difference is once an instruction/CSR has been defined in x86 or ARM the only two options are a) it doesn't exist, and b) it's that instruction.
In RISC-V it can be anything even after it has been defined.
Actually... I say that, but they do actually reserve spaces in the CSR and opcode maps specifically for custom extensions so in theory they could say it's only undefined behaviour in those spaces and then you would be able to probe in the standard spaces. Maybe.
I think they just don't want people probing though, even though IMO it's the most expedient solution most of the time. Otherwise you have to go via an OS syscall, through the firmware and ACPI tables, device tree or mconfigptr (when they eventually define that).
On getting supported extension status - there's a C API spec that could potentially become an option for an OS-agnostic way: https://github.com/riscv-non-isa/riscv-c-api-doc/blob/main/s.... libc already will want to call whatever OS thing to determine what extensions it can use for memcpy etc, so taking the results from libc is "free".
Not any different from C - a given C compiler + platform will behave completetly deterministically and you can test the output and see what it does, regardless of UB or not.
> a given C compiler + platform will behave completetly deterministically and you can test the output and see what it does, regardless of UB or not.
Sure[1], but that doesn't mean it's safe to publish that C code - the next version of that same compiler on that same platform might do something very different. With machine code (especially x86, with its very friendly memory model) that's unlikely.
(There are cases like unused instructions becoming used in never revisions of a processor - but you wouldn't be using those unused instructions in the first place. Whereas it's extremely common to have C code that looks like it's doing something useful, and is doing that useful thing when compiled with a particular compiler, but is nevertheless undefined behaviour that will do something different in a future version)
[1] Build nondeterminism does exist, but it's not my main concern
CPUs get microcode updates all the time, too. Nothing is safe from bitrot unless you’re dedicated to 100% reproducible builds and build on the exact same box you’re running on. (…I’m not, for the record - but the more, the merrier.)
> CPUs get microcode updates all the time, too.
To fix bugs, sure. They don't generally get updates that contain new optimizations that radically break existing machine code, justifying this by saying that the existing code violated some spec.
>To fix bugs, sure.
Maybe your program worked due to the bug they fixed.
Extremely unlikely. CPU bugs generally halt the CPU or fail to write the result or something like that. The Pentium FDIV bug where it would give a plausible but wrong result was a once in a lifetime thing.
Spectre and Meltdown exploits stopped working, too. Some of them on some CPUs, anyway.
Sure. But those were obviously exploits from the start. You wouldn't write code like that accidentally.
Do a web search for rdrand and systemd.
> Do a web search for rdrand and systemd.
RDRAND always returning all-FF is exactly the kind of thing that's an obvious bug, not a plausible-but-wrong result.
The other guy said "Maybe your program worked due to the bug they fixed.". The RDRAND fix achieved exactly that.
It is not terribly hard to generate C code that does not use undefined behavior.
Maybe. But when carefully investigated, the overwhelming majority of C code does in fact use undefined behaviour, and there is no practical way to verify that any given code doesn't.
It is easy to create code where this can be verified. It is difficult to verify for arbitrary code.
No.
How can one be assured that all of the compile-time safety features of Java are is still in effect in bytecode?
The JVM class loader verifies the bytecode:
https://stackoverflow.com/questions/755005/how-does-bytecode...
It verifies bytecode for bytecode rules violations, not that it matches original Java source code or whether original source code is safe.
Because they happen at compile time?
It's as safe as LLVM IR is safe, assuming you trust the LLVM IR -> C translation step.