Any tutorial for C should explain compiler warnings and other tools that help make code safer. In C, you do not rely on the language specification but on tooling. Especially for Rust programmers, this needs to be explained more explicitly. And of course, you can build abstractions using types in C. So a tutorial should also focus on that, and perhaps not start with a low-level string reversal function.
Absolutely. Turn the warnings into errors too, build and test with sanitizers (ASAN, UBSAN, TSAN) when not measuring performance, and use static analysis beyond compiler warnings (Clang Tidy, Clang Static Analyzer).
Though the author doesn't look to be trying to write a great tutorial, rather prioritizing sharing what and how they learned something from their perspective.
I'm with you. Since the post already shows Clang catching the array-decay bug, the author could even just add a “always build with -Wall -Wextra -fsanitize=address,undefined” note and some explanation of course.
The way C handles (prior to C23) booleans is pretty close to how you'd handle booleans in assembly.
CPUs don't have types, everything is integers or floats. You do your work on registers which have fixed sizes. CPUs have built in instructions for "is this register not zero" which leaks into C. 1 is true in C, but so is 2.
Also, single bits are rarely used for booleans because it requires more CPU power to extract a single bit. Everything is byte aligned at a minimum.
When doing something like network code, if you want to store a bunch of booleans you are typically going to either pack them into a byte, or you'll burn the extra bits and send a single byte for the boolean value. Typically this was flags and masks.
It's beautiful to see this perspective! The fact that we are at "whoa, C is fucked up compared to my expectations" instead of "look at Rust's fancy safety stuff" shows that as a field we've started lifting the baseline.
Nowadays I actually believe I'll likely see a world without memory corruption within my lifetime.
Focusing narrowly on memory safety is frequently a distraction that incompetent developers use to excuse their buggy code. "Sure, my Rust code might cause deaths and cause millions of dollars lost; and my code might be unsafe, insecure and incorrect; but at least my code is memory safe and easy to debug when I fuck it up!". And then it often turns out that Rust is not memory safe in practice. https://news.ycombinator.com/item?id=49697392
The real value of Rust is likely pattern matching and tagged unions. Apart from modules/packages that are not a disaster, like Gabriel Dos Reis the saboteur's disaster with modules in C++.
My take too. (Aside from this being a well-written, clear article, that I think highlighted a fair selection of relevant points; especially the "always use uint8_t instead if int" part).
I don't see rust a "memory safe" language, or a niche one. I have complaints about it etc, but it's overall a fair baseline of reasonable decisions. When I look at C or other languages rust has learned from, I have more "Yikes, that's rough" takes. So... rust as the language of least "fucked up", to use your phrase? Ownership/safety are one part of the picture, but not what defines it for me.
It’s definitely great that memory safety is becoming more pervasive. Though I’ll believe “a world without memory corruption” right up until another <insert your relevant hacker hero name> comes along and finds a way through an unsafe block, an FFI boundary, or the hardware itself (Rowhammer says hi).
Yeah I was thinking of prefixing my "memory corruption" with "software-bug induced"! I don't see a credible solution to Rowhammer. ("DDR[n+1] fixes it" - lol)
> an unsafe block, an FFI boundary
Honestly these feel solvable to me at this point! I think we'll see:
- unsafe code shrink as languages get more powerful
- amount of analysis we can apply to each unsafe line shoot up exponentially as AI gets cheaper
- amount of FFI we actually need shrink as it gets easier to just click "rewrite it in $lang" on the decision card when your coding agent says "I found a library for that but it's in a different language"
(Having said all of that, people seem to be adopting Zig for some bizarre reason... So maybe I'm naive to expect unsafe lines to shrink)
(But also, maybe AI gets so good and so cheap that we can just type "go fidn all the bugs andfi xthenm" into an LLM, between sips of a Piña Colada)
>The very first systems programming language I ever learned was Rust. This is uncommon compared to many other programmers; you're more likely to find someone who learned C or C++ first before coming to Rust.
It's becoming increasingly common. Rust is my first systems programming language too. I tried to learn C a few years ago but I found it too austere and prickly, which put me off.
I was going to write that I found this odd. The kid that cuts my grass is going for a degree in CS and told me just yesterday that, in his second year, Java is the language he uses with a little Python. That C was such a struggle and he won't touch it.
For someone getting a CS degree, that just seems so, so odd. Along with that, he's been studying edge detection in images. In his second year. Not to run off topic but, again, I find that so, so odd.
Probably because C and C++ are mostly used in system and desktop development.
Rust is taking steps or has been taking steps in this direction too.
It's not surprising that a lot of experienced systems and desktop development engineers looking to getting their hands on the newest tool already have experience or at least familiarity with C and C++.
One of my favorite things to show just how bare this is in C is to show array access commutativity.
C is wonderfully simple at times.Though the author doesn't look to be trying to write a great tutorial, rather prioritizing sharing what and how they learned something from their perspective.
If malloc() fails, there is no need to exit the program completely with exit(), only return from the current function with an error.
That boolean is actually mostly an extension of the integer system whereby we now have an integer type that stores only one bit.
Whereby the bit stored either results in a 'true' or 'false' value.
Anyways, I know booleans are useful in systems development when you have strict memory / storage constrains / bandwidth (networks).
Yeah, that works for me.
CPUs don't have types, everything is integers or floats. You do your work on registers which have fixed sizes. CPUs have built in instructions for "is this register not zero" which leaks into C. 1 is true in C, but so is 2.
Also, single bits are rarely used for booleans because it requires more CPU power to extract a single bit. Everything is byte aligned at a minimum.
When doing something like network code, if you want to store a bunch of booleans you are typically going to either pack them into a byte, or you'll burn the extra bits and send a single byte for the boolean value. Typically this was flags and masks.
SQL Server still has no boolean type and groups bits in the same row into a byte if possible.
Meaning, if you have a struct and you want to bit-pack your booleans, you can declare each one as, say, uint8_t some_bool : 1;
You may then do `x.some_bool = true;` etc.
It's a small nicety to avoid bitwise operators, anyway.
Nowadays I actually believe I'll likely see a world without memory corruption within my lifetime.
The real value of Rust is likely pattern matching and tagged unions. Apart from modules/packages that are not a disaster, like Gabriel Dos Reis the saboteur's disaster with modules in C++.
I don't see rust a "memory safe" language, or a niche one. I have complaints about it etc, but it's overall a fair baseline of reasonable decisions. When I look at C or other languages rust has learned from, I have more "Yikes, that's rough" takes. So... rust as the language of least "fucked up", to use your phrase? Ownership/safety are one part of the picture, but not what defines it for me.
Yeah I was thinking of prefixing my "memory corruption" with "software-bug induced"! I don't see a credible solution to Rowhammer. ("DDR[n+1] fixes it" - lol)
> an unsafe block, an FFI boundary
Honestly these feel solvable to me at this point! I think we'll see:
- unsafe code shrink as languages get more powerful
- amount of analysis we can apply to each unsafe line shoot up exponentially as AI gets cheaper
- amount of FFI we actually need shrink as it gets easier to just click "rewrite it in $lang" on the decision card when your coding agent says "I found a library for that but it's in a different language"
(Having said all of that, people seem to be adopting Zig for some bizarre reason... So maybe I'm naive to expect unsafe lines to shrink)
(But also, maybe AI gets so good and so cheap that we can just type "go fidn all the bugs andfi xthenm" into an LLM, between sips of a Piña Colada)
Why would a Rust programmer learn C? Isn't that basically a regression?
It's becoming increasingly common. Rust is my first systems programming language too. I tried to learn C a few years ago but I found it too austere and prickly, which put me off.
For someone getting a CS degree, that just seems so, so odd. Along with that, he's been studying edge detection in images. In his second year. Not to run off topic but, again, I find that so, so odd.
Rust is taking steps or has been taking steps in this direction too.
It's not surprising that a lot of experienced systems and desktop development engineers looking to getting their hands on the newest tool already have experience or at least familiarity with C and C++.