5 ms·
I'm confused as to why it's such a big deal to learn C. It's not a very large or complex language. If you already know how to program, there isn't that much to
by whateveracct 3y ago
I'm confused as to why it's such a big deal to learn C. It's not a very large or complex language. If you already know how to program, there isn't that much to learn to understand C (pointers aren't complex).
It's also a fine beginner language, especially in a structured university setting imo.
Yes, you probably don't need to learn it. But it can come in handy. For instance, there's a wealth of useful software out there in C. It's nice to be able to read its source, hack on it, or leverage it from your higher-level language via FFI.
- jszymborski 3y agoI haven't tried writing C(++) in ages, but what recall being a giant irritant was the tooling. Writing simple programs was fine enough, but the whole matter of linking libraries and writing Make files was a headache.
- alexhutcheson 3y agoThis is a huge pain point. If you're writing small programs that fit in a couple files in a single directory, then you can get by with manual invocations of clang or gcc at the command line. If you want to build anything of moderate complexity, then you need to get familiar with all the complexity of a separate build system like Make/CMake/Bazel/etc. Java has a similar problem - once your program grows beyond ~1 directory, you end up needing to learn Maven/Gradle/etc. Build and testing tooling is one thing that younger languages have generally done much better. Rust, Go, Dart and others all have standard build tools integrated with the language that scale to large projects, with standard testing frameworks integrated with those tools. Scripting languages like Python have import features within the language itself. Much lower cognitive overhead.
- shrimp_emoji 3y agoAre you suggesting `cargo test` is somehow any simpler and nicer to use than `cd build/ ; cmake ../src/ && make -j100 && ctest`?
- theamk 3y agoThis is a huge pain if you want to support multiple systems, which most of the biggest products do. But if you (1) choose a single OS, (2) have "few" (say under 20) files and (3) rely only on OS-provided libraries, then things are actually pretty simple. For example, you only support Ubuntu 20.04 or Fedora 39. Then your makefiles are nice and easy to read, and you just rely on pkg-config for the libraries.
- whateveracct 3y agoI Nixify all the C I work with. It has good, automatic support for all the common tooling setups.
- jacurtis 3y agoC syntax is limited and therefore "simple". Building advanced data structures and programs with your limited toolset does require some out-of-the-box thinking. This is partially why C is a common teaching language. Because you have to build a lot of tools that are easy to take for granted in other languages. Take a Map or Dictionary for example. C doesn't technically speaking provide one, so you learn to implement them pretty quickly and often. Technically speaking C doesn't even have a primative string type, you just create an array of chars, which by the way has to be a pointer. While this is super easy to do once you've seen it once or twice, it teaches you how strings work in almost every other language. The reason you can trivially loop through a string in python, is because it works the same way, they have just abstracted it a tiny bit from you. Now to the author's point... does that really make you a better developer to know that? Therefore is it really needed? No probably not needed. But these exercises and experience does help solidify more complex topics later on. So you don't need C, but I still think there's benefit in learning it.
- shrimp_emoji 3y ago> Take a Map or Dictionary for example. C doesn't technically speaking provide one, so you learn to implement them pretty quickly and often. I take issue with the "quickly and often" part, but you do learn to implement them! And that provides valuable insight when it comes to other languages. I've had senior devs who, like past me, didn't understand why removing an element from a vector or map invalidates iterators or indices on it. I learned precisely why when implementing vectors in C: the usual implementation of those collections shifts everything around to maintain element contiguity in memory, so now your iterator/index is pointing to a different element (which incrementation will skip) or possibly past all the elements! And when you're presented with these fancy data structures in Java or Python, that feels unintuitive and wrong. "Come on; I should be able to just iterate through this and remove certain elements as I go," like you would remove objects from a shelf. The shelf doesn't rearrange the objects after you take one out! But the reason it feels like an affront to common sense is that you've been trained to take the fancy data collections for granted and not forced to understand the complexity behind them that makes them efficient. Of course, the real answer is to do that with some functional algorithms, like `std::remove_if()`, instead of via iteration. That way, you'll really be in the cloud-scraping ivory tower and never have to think about what's going on below. https://youtu.be/ggijVDI6h_0 https://youtu.be/ggijVDI6h_0 :p
- hashtag-til 3y agoThe point may be that time is a scarce resource and you better focus on what's important for you. C may be it, but I think Ned's point is that people might be learning C thinking it will give them a skill that it actually doesn't.
- whateveracct 3y agoI find thinking about time like that ends up counterproductive. You can read K&R and code/read a little C and never build a single thing in it and have it be worth it. For instance, I wrote C in school but basically never use it professionally or for my hobbies (directly at least). But I'd say learning it was worth it - my school curriculum didn't "waste" my scarce resource of time. You do end up learning to think about computers in a different way.
- bluetomcat 3y ago> pointers aren't complex They are complex if you are coming from the Python world. To truly know their recursive declaration syntax, you have to see it from a compiler's perspective. Pointer arithmetic isn't something you do often even in C++. It's a crude kind of reference that can be mutated arithmetically and doesn't provide any safety whatsoever. It maps well to the indirection mechanisms and addressing modes provided by the underlying hardware.
- seba_dos1 3y agoEverything is complex when you're barely starting, but in general, pointers aren't complex. Don't mistake the complexity with ease of making mistakes though.
- alexhutcheson 3y agoHonestly I find Python's value vs. reference semantics fairly confusing, and it's not always obvious whether an operation is going to make a copy or modify an existing instance of an object. Good API design and docstrings mitigate this, but it's one more source of complexity to think about. I run into this much less frequently in C++ code - it's normally pretty clear from parameter and return types whether I'm dealing with a copy or a reference. This might just be because C++ broke my brain into assuming: Object foo = other_object; is a copy operation, and taking a reference or pointer would require extra characters (e.g. copy by default). Most other languages are the opposite: assignment creates a reference by default, and making a copy would require extra characters (e.g. .copy() in Python or .clone() in Java). That's my biggest mental adjustment when moving back-and-forth between C++ and Python.
- nedbat 3y agoPython itself only has one kind of argument passing (neither by-value or classic C++ by-reference), and nothing is copied. Library functions could make confusing choices, it's true.
- chasil 3y ago> pointers aren't complex It really helps if you understand assembler addressing modes. Then it makes total sense.
- theamk 3y agohuh? I work with pointers all the time, and I don't think I ever cared about assembler addressing modes.. Who cares if you pre-increment in the same instruction or if you need a separate operation for that? Who cares if offset is computed as part of the load or separately? This does not change how the program is built or debugged. (Unless you are talking about x86 real mode segment registers. Luckily, we can leave this behind and never talk about them again :) )
- xigoi 3y agoPointers aren’t complex, but C makes them look complex with the counter-intuitive syntax. Therefore, I don’t think C is a good language for learning pointers.
- camgunz 3y ago> there isn't that much to learn to understand C Man, what a bold claim. I could say all kinds of things about the number of books written about C, the size and complexity of its compilers, the failure of even veterans to avoid mistakes, the constant disagreement amongst even experts about the most fundamental things like realloc, but my only argument--indeed the only argument I need--is that the standard [0] is literally hundreds of pages. > pointers aren't complex Pointers are so complex they're responsible for the vast majority of security bugs across all of computing history, and they're so powerful and overloaded that they can't be fixed without bonkers hardware interventions like CHERI. You might say, "nah it's buffers" but when you have a pointer, everything is a buffer! You might further say "nah it's random undefined behavior", but it's very, very hard to use a pointer without invoking undefined behavior. Here's a quick thing I googled: int func(int **a) { *a = NULL; return 1234; } int main() { int x = 0, *ptr = &x; *ptr = func(&ptr); // <-??? printf("%d\n", x); // print '1234' printf("%p\n", ptr); // print 'nil' return 0; } Did you know that the language doesn't specify whether the deference on the left of `*ptr = func(&ptr);` comes before the address-of on the right, thus this behavior is undefined? Can you really be arguing that this isn't complex? Look I love C, but it's deeply complex and a lot of that is pointers. [0]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3054.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3054.pdf