Hacker News new | ask | show | jobs
by nicoburns 2297 days ago
Do any of these resources help with learning how to deal with:

1. The lack of abstractiom in C? 2. All of the pitfalls and gotchas: Undefined Behaviour, use after free, etc?

I've been writing Rust for a couple of years now, so I'm quite comfortable with low-level ideas, memory management, etc. But C still scares me because it seems so easy to make mistakes, and I also often find it hard to see the forest for the trees.

Perhaps C's just not for me?

5 comments

I think both “Expert C” and “Modern C” do a reasonably good job working through memory management patterns, strategy, and constructs. However, I’m using this comment as an attempt discuss another topic you raised in your comment.

I don’t mean for this to be flame bait, but I do think it is worth pointing out and discussing if you desire. The concept of memory management that is presented in a majority of the Rust that I have seen written outside of deep library code and the parts of the low-level implementations of some standard library functions has very little relation to the analogous concepts in C. I’d say that what Rust considers memory management in average code is more similar to programming in C without using any heap allocation. I could be wrong or could just have not seen the right code bases, but there is very little C style byte level ‘data structure’ layout design and then the allocation of those sorts of data using multiple allocation strategies.

I certainly understand that the above mentioned constructs and patterns are really not part of Rust’s idiomatic usage, and that a chunk of C’s allocation options are semi-prohibited because of Rust’s memory model. But, if you are coming from Rust and going into C, the differences are far greater than the similarities in this area.

I’m certainly not questioning your credentials, experience, or ability, I really just feel like this area is lacking any substantial discussion where said discussion is not focused on the merits/drawbacks of the language design. You clearly know Rust and seem to be open to learning or working with C, so it isn’t about Rust v. C, it’s about compare and contrast, and highlighting the fundamental differences that could cause some mental roadblocks.

P.S. Sorry for rambling, Day Light Savings time is kicking my ass.

Not parent but Rust definitely makes you think about a lot of important aspects of memory management like lifetimes and references and ownership and stuff. In fact, it makes it impossible not to think about them: they're enforced by the compiler.

Those mechanics are pretty important but Rust definitely lets you program with values on the heap as well, it just does it in a strongly-typed fashion. I will agree that smart pointers are generally easier to work with, particularly with things like deref coercion, but Rust is philosophically closest to a language like C++ but with a stronger type system, memory safety, and lots of footguns removed.

I think Rust gives someone a better basis for learning and writing C than probably any other modern language.

I grokked C only after dabbling with Forth. C is too high level to know what's going on at the hardware level.
Most processors these days are basically running C virtual machines in hardware anyways.
> I could be wrong or could just have not seen the right code bases, but there is very little C style byte level ‘data structure’ layout design and then the allocation of those sorts of data using multiple allocation strategies.

My experience is mostly in very high level languages, C#, TypeScript, SQL, so that's probably reflected in the style of Rust code that I've been writing, but at least as one data point, yes, it is very possible to write day-to-day Rust code without getting into byte level data layout.

It does feel a lot like writing C code without using a heap. In fact the only case I've dealt with allocating uninitialised heap memory so far has been when interacting with a C API. Creating a new Vec does allocate memory on the heap (once values are pushed into it), but as a user it feels like passing around any other stack allocated struct. I think this is mostly due to the RIIA-style Drop and ownership system, as there is no extra code to free a value that owns a heap allocation vs a stack-only value.

The implementation of std::mem::drop is a fun example of this: https://doc.rust-lang.org/std/mem/fn.drop.html

Yes. Or, at least, the second part.

I'm not sure what you mean by "lack of abstraction in C."

"Abstraction" is not a straightforward property of a language; it's a thing you create with programming languages. It's true that some languages make it easy to express certain kinds of abstractions, but C has it's own way of abstracting things, and it's certainly not absolutely obvious that its way of doing so is inferior to others.

Sometimes making mistakes is a good way to learn, provided that you get feedback to help you identify them.

You can compensate for C's lack of compile time protections with run-time tools like valgrind [1] and the various sanitizers in clang [2, 3].

1: http://valgrind.org/

2: https://clang.llvm.org/docs/AddressSanitizer.html

3: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html

There is an old but great book called "C traps and Pitfalls" on that subject.

Otherwise you're left alone with yourself and your tooling. Things like valgrind help a lot. But I'll admit that I too find large C projects alarming; it may be better to write "C with classes" code in a C++ environment, so at least you have classes and namespaces as an organisational tool.

I recommend Bradley's 'programming for engineers: a foundational approach to C and Matlab'. Simple book with relevant exercises.
If a book on C is described as "simple" I bet it's not about doing things right (which is what OP is worried about.) Doubly so if it covers something in addition to C.