6 ms·
> Terseness, sure, but not simplicity. I feel the same whenever somebody shows up talking about their favorite functional language. Sure it can be less code, b
by deeviant 5y ago
> Terseness, sure, but not simplicity.
I feel the same whenever somebody shows up talking about their favorite functional language. Sure it can be less code, but it looks like an explosion at the unicode factory.
Really though, I'd much rather have a few language "gotchas" that you need to learn once, over countless gotchas in other developers code because they are using a language the lends itself to ungrokable code. C really does have the properly where you can look at the code and just know what it does.
That said, I don't think C scales very well for big projects and I personally develop in C/C++/Python/ environment as a robotics system SWE. C for embedded stuff, C++ for nearly all system code, and python for the data/Deep learning stuff.
- deleted 5y ago[deleted]
- AstralStorm 5y agoC does not have that property of not having gotchas whatsoever due to how undefined behavior is handled. (Or rather not handled) plus compiler and architecture defined behavior. If you can spot undefined and other platform defined behavior always, someone probably would want to hire you as a security specialist.
- astrange 5y agoIn current C this is actually undefined behavior: uint8_t start = -1; uint64_t result = start << 24; however there's some hope of defining it once C requires 2's-complement integers. (this wasn't reasonable in the past but is now) There are worse problems with `a << b` because the shift instruction on CPUs doesn't actually treat b as an 'int', it reads the lower X bits and uses that. C can't define what X is because not only is it different in x86 and ARM but x86 doesn't even match itself - it's different for scalar and SSE ints.
- nayuki 5y agoNo, this is not always undefined behavior. uint8_t start = -1; // Your code uint8_t start = 0xFF; // Absolutely equivalent As for the expression `start << 24`, `start` will always be promoted to `signed int` because `int` is guaranteed to be at least 16 bits wide, so it can hold all `uint8_t` values. If the width of `int` is 32 bits or narrower, then `start << 24` (which is 0xFF000000) will put a binary 1 into the sign bit, which is indeed undefined behavior. Otherwise if `int` is 33 bits or wider, then `start << 24` will fit in `int` nicely and be fully defined behavior. Reasoning about these complicated cases involving implicit conversion (-1 -> 0xFF), promotion (uint8_t -> signed int), and implementation-defined bit widths (how wide is int?) is exactly why I dislike dealing with C and C++.
- astrange 5y agoWhere have you found an ILP64 system? There aren't any - that's why I said "current C". The idea that C programs can survive having the size of their most common type changing is not realistic, though luckily people rarely try.
- nayuki 5y agoYour insistence on "current C" is a brittle claim to make. I'll give you the benefit of the doubt that there are no popular instances of ILP64 systems today. But someday your comment will be false, and it could happen at a surprising time. This would be a repeat of how old C programmers' false assumptions were violated by the 16->32 bit transition, the 32->64 bit transition, and the increasing exploitation of UB for optimization. Whereas my comment is always true with respect to the C11 standard - there can be a legal implementations where `(uint8_t)-1 << 24` is undefined behavior, and other implementations where it is well-defined behavior equal to 0xFF000000. As for writing code that behaves correctly on any legal C implementation, it is certainly possible and I practiced this for years. Go ahead and audit my published programs. It is not easy though, and I have made many mistakes along the way before I figured out how to do it consistently. Although there are many rules that I need to follow, the two most important ones are: Obey the fact that built-in integer types have minimum widths (e.g. char is at least 8, int at least 16, long at least 32); Use size_t for array lengths and indexes.
- deeviant 5y agoThat there is a chance of undefined behavior is a statement without worth or meaning. It's like having an estimation method without an error bound. In my experience, I run into "undefined behavior" in C-land extremely rarely. I can't remember a single instance in 15 years of embedded programming (unsigned/type promotion sure everybody does that at least once sometime, some weird architecture defined thing, nope). Maybe that's because I'm some super amazing C programmer, or that I read the docs, or maybe it's because the chance is low? Regardless, people very often become hyper-focused in this types of debates to be point of being completely unbraced by reality. The valid way to do these sorts of language comparisons is to look at the the pros and cons and give them a weight. Something like this pro is (very good), but (rarely comes up in practical programming), or (This con is very bad) but basically only shows up in (interview questions), etc. Then take the sum of the weight of each side, rather than making statements like, "language has/doesn't have x feature/drawbrack thus I'm right about every thing yay!". I.e. if you are looking at a 10d problem in 1d, you're going to be wrong.
- mbrodersen 5y agoC seems to scale very well for the Linux kernel?