Aimed at Rust programmers learning C, the write-up catalogs practical surprises and gotchas encountered when switching languages. It highlights historical and standard differences - booleans were added via stdbool.h in C99 (true/false are macros expanding to 1/0) and only became language primitives in C23. Strings are null-terminated rather than fat pointers: C relies on a trailing '\0', so code must allocate space for the terminator, empty strings occupy one byte, embedded nulls break C string functions, and forgetting the terminator can cause out-of-bounds reads (example: using strlen and malloc(len+1) when reversing a string).
Concrete language pitfalls are covered: integer type widths are target-dependent (notably long is 64-bit on Unix but 32-bit on Windows), so prefer fixed-width types from stdint.h and size_t/ptrdiff_t for portability. Error handling relies on magic return values and errno instead of enforced Result-like types, so failures can be easily ignored. Field access uses . for values and -> for pointers, arrays decay to pointers when passed to functions (affecting sizeof and often producing 8-byte pointer sizes), and there are no references or borrow checking - only raw pointers and pointer arithmetic. These specifics give a practical checklist of what to watch for when writing C after Rust.
Summary generated by AI from the linked article. hn.today is not affiliated with Hacker News or Y Combinator.