C's One-Size-Fits-All String vs. Rust's Entire Wardrobe
Description
A technical meme presented as a two-column table. The left column is titled 'For this type in C...' and every single one of its 13 rows contains the same entry: 'char *'. The right column, titled '...use this type in Rust', lists a different, specific Rust type in each row that corresponds to a potential use case of C's 'char *'. The list includes '&str', 'String', '&[u8]', 'Vec<u8>', 'OsStr', 'OsString', 'Path', 'PathBuf', 'CStr', 'CString', and '&'static str'. The humor is rooted in the contrast between C's simple but dangerously ambiguous approach to strings (a single pointer type for everything) and Rust's highly explicit, safe, and specialized type system. For developers experienced in both languages, this table perfectly encapsulates the migration pain and the philosophical shift from C's 'trust the programmer' model to Rust's 'make invalid states unrepresentable' mantra, highlighting the complexity that arises from ensuring memory safety and correctness at the type level
Comments
24Comment deleted
In C, a `char *` is a promise the programmer probably won't keep. In Rust, the fifteen different string types are a binding legal contract drafted by the borrow checker's paranoid lawyers
char* was the monolith; Rust split it into 13 microservices and made the compiler your SRE
After 20 years of debugging segfaults from char* arithmetic, you finally switch to Rust for memory safety, only to spend the next 20 years in therapy trying to understand why a simple string needs a PhD in type theory and a flowchart to decide between &str, String, OsString, CString, and their 47 cousins
Ah yes, the classic 'char *' - C's Swiss Army knife that's actually just a rusty butter knife. Meanwhile, Rust looked at this situation and said 'hold my borrow checker' before spawning 13 distinct types, each with its own lifetime guarantees, ownership semantics, and UTF-8 validation. Because nothing says 'we learned from C's mistakes' quite like having separate types for owned OS strings, borrowed OS strings, owned paths, borrowed paths, and that one &'static str that'll outlive your entire codebase. The real joke? After 20 years of C++, we're still debugging segfaults from char*, while Rust developers are arguing on Reddit about whether to use &str or &[u8] for their perfectly safe, zero-cost abstraction
Porting C: every char* turns into a design meeting - &str? String? &[u8]? CStr? OsStr? PathBuf? - and you realize the pointer was eight different APIs pretending to be one
C's char*: one ring to rule them all. Rust: eleven strings, each demanding its own lifetime annotation
C gives you one char*; Rust makes you pick the encoding, ownership, and lifetime - because in Rust, ‘undefined behavior’ is just an unacceptable type signature
Yeah, and thats beautiful. Comment deleted
The fact that there's C-string type in rust... Comment deleted
Cuz s strings are bit cursed, and ffi glue is needed Comment deleted
C-string is something zero terminated, of im not mistaken Other things store their size explicitly and dont need any terminator sign Comment deleted
yeah. They probably called conventionally c-string cuz of low level api's written in C that require you to pass zero-terminated strings only Comment deleted
you forgot about raw pointers Comment deleted
Nothing like a crash because you specified the wrong atray size lolol Comment deleted
CStr and CString is not the same thing in Rust?! 🤯 Comment deleted
So the only difference is whether it is an owned or a borrowed object? (Because semantics is only different between String and CString then.) Comment deleted
also CStr has no guarantees about validity Comment deleted
So you need a long time to learn these 😐❤️ Comment deleted
You don't need to learn them. Youll find them out when you need them. Normally u only interact with String or its bytes repr. Others are for this or that exotic task. And on the left we have char*, which is pretty much useless by itself(youll still use some wrapper from 3rd party lib for the serious project). Comment deleted
No, because you don't need Rust. Comment deleted
&'static str is &str with static lifetime (compile-time known strings, usually) Comment deleted
Path and PathBuf represent borrowed and owned OsString which is a path Comment deleted
Fixed length arrays do not need to lie behind some kind of a reference or another fat pointer Comment deleted
Also, although &str is a stak object, it has only two values on the stack - internal pointer to string beginning and slice size Comment deleted