17 ms·
How is it less compact and simple than it was 10 or 20 years ago? It's still the same language, in spirit and in practice.
by jstimpfle 5y ago
How is it less compact and simple than it was 10 or 20 years ago? It's still the same language, in spirit and in practice.
- pjmlp 5y agoExcept K&R C will stop compiling in C23, and is so simple that most people that think they know C, will fail in all glory a pub Quizz that contains all ISO C versions and major language extensions.
- jstimpfle 5y agoK&R C is not 10 years ago. It's 30-50 years ago and (AFAIK) wasn't even properly standardized and (AFAIK) still mostly works with recent compilers. Everybody thinks they know shit and yet they don't know all the details even after 5 years of practice (and let's not even look at C++!). Welcome to reality. However, a programmer's goal is not to know all the (often irrelevant) details. And it's not to win a pub quiz. The goal is to know enough to be able to communicate ideas in a clear and straightforward way, and to be productive.
- pjmlp 5y agoAh it isn't so simple after all. Than lets limit the questions to what is UB, which is needed for daily programming activities, specially when one cares about security assessments, I am betting on the same outcome.
- jstimpfle 5y agoThis has nothing to do with K&R or whatever new C standard there is. You're talking trash. The rules around UB can be annoying, but I don't think this is a recent development, either. Probably compiler optimizations are to blame for some of this. For actual practice and pedestrian code, obscure UB bugs have little relevance. Food for thought: C compilers are free to insert runtime checks to abort when UB occurs.
- vlovich123 5y agoUB was standardized in C99 and optimizers started really going after it maybe 5-10 years after that. There was a wide spread push to make the issue more widely known 8 years ago-ish if I recall correctly and most people still don’t fully understand it. I wouldn’t say it’s “new information”, but it’s certainly relatively new in the overall lifetime of the language (ie even a lot of C99 code from that era is malformed on today’s compilers). I understand the basic concept of UB but some of the rules can have nuance and be easy to run afoul of. If you’re not running UBSAN on non-trivial codebases (lots of LOC and/or multiple devs), you are likely to have UB. Same goes for ASAN and TSAN issues. I always have humility around this topic as I’m not a compiler author. Heck, the compiler authors I’ve worked with themselves know the knives are sharp and work with humility.
- jstimpfle 5y agoTotally agree with your post. I don't know what your conclusion is, though. My conclusion is that C lets me do what I want straightforwardly, I still haven't found this quality in a different language (there is inertia, I've only tried Zig for an hour for example and gave up in frustration). Also, to some degree I understand where most UB definitions are coming from and even agree with some of them. The basic idea behind UB is to give the compiler a free pass (optimization, and not having to detect corruption) if the program has a bug anyway. In some cases there can be legitimate surprises, when the programmer made some assumptions about guarantees that C can't give and that a newer language (without the historical baggage of supporting some architecture) can give, which might result in the compiler transforming a little bug into something bigger (more dangerous?). An example that I've personally learned at some point is integer shifting and masking in conjunction with implicit type promotion to int (which is signed). All in all though, while I'm not be the most sophisticated programmer and most of my programms are never exposed to hacking attempts, just anecdotally I've had very, very little headaches from UB.
- vlovich123 5y ago> My conclusion is that C lets me do what I want straightforwardly, I still haven't found this quality in a different language C is the language where you've found things to be straightfoward? I'm curious what you're working on where this is the case. I'd reach for Python, Go, Java, Swift, C#, depending on what I'm trying to do (even C++ can be better, but it comes with its own unique additional set of footguns so some C acolytes tend to shy away from it). For most projects (at least those starting from scratch today) I'd probably choose Rust if C/C++ would otherwise be the only appropriate choice & use Python/Go/Swift/Java/C# elsewhere. > All in all though, while I'm not be the most sophisticated programmer and most of my programms are never exposed to hacking attempts, just anecdotally I've had very, very little headaches from UB. and > An example that I've personally learned at some point is integer shifting and masking in conjunction with implicit type promotion to int (which is signed). Is an interesting mix of statements. I can say that I've worked on quite a few large codebases with a myriad of contributors, & I've always uncovered UB when I went looking for it. Some of it harmless, others less so. It's a "this probably is invisible 90% of the time you run it locally" kind of thing, so unless you have thorough tests you can run under UBSAN, you're likely just unaware of the scope of the problem. That being said, I don't want to blow it out of proportion. I'd say memory safety & thread safety are bigger classes of issues. As with UB, if you're not running sanitizers with very large test suites, you're unlikely to see it [1][2]. As for why UB is a real problem conceptually, this used to be well-formed and correctly behaving pre-C99: ``` uint8_t x = <pointer to some buffer> uint64_t y = (uint64_t)x; ``` I don't mean in a "this just happened to work" but in a "this was valid semantics of the language". Now it requires a memcpy. It's also entirely possible this is valid in C & not C++? That's what I mean by UB being very subtle. Yes, I understand why UB is important to allow compilers to generate more optimal code. I think Rust strikes a better balance here - most code doesn't* need that tradeoff and where it's important can be explicitly annotated with that fact. Ultimately, to me the fact that even the Linux kernel is subject to these kinds of issues[3], gives me enough pause to believe it's a real problem in the ecosystem (among many others). So other, safer languages, are usually better if you can use them. Most experienced developers should have a number of languages under their belts they're fluent in and be able to switch to languages they haven't seen before (albeit there's always a cost & it's not fun, so I don't seek it out as often as I maybe should). [1] https://reviews.llvm.org/D51170 https://reviews.llvm.org/D51170 [2] https://bugs.llvm.org/show_bug.cgi?id=23293 https://bugs.llvm.org/show_bug.cgi?id=23293 [3] https://software.intel.com/content/www/us/en/develop/blogs/null-pointer-dereferencing-causes-undefined-behavior.html https://software.intel.com/content/www/us/en/develop/blogs/n...
- tialaramex 5y agoI mean, that's nice and everything, but you're the one who brought up pre-standard (K&R) C. I have a copy of the 2nd edition "The C Programming Language" by K&R from 1988 which discusses what is in effect the standard C89 language. Appendix C calls out the substantive changes compared to their earlier book, it is three pages long. It's true that these changes are significant, C would be a very different language without enum for example, or with "old-style" (already deprecated by the time the book was written in 1988) function declarations. But the language is still very compact. The book explains and describes essentially the entire language, and outlines the standard library, in under 300 pages. Only a few years later, the 2nd edition of Stroustrup's book "The C++ Programming Language" is more than twice the length, and introduces numerous already anachronistic features in notional support of C, which had meanwhile deprecated them. This takes up about 700 pages. Stroustrup not only grandfathers in features C had by then cast off (such as weird function definitions) but also introduces crazy nonsense that I hope nobody ever used in the name of "backward compatibility" e.g. hey why not overload both of the increment operators (themselves bad ideas C++ inherited from C) with the same function? Imagine trying to pretend to yourself that you believe this is a reasonable thing to do, while also pretending to believe operator overloading delivers "unsurprising" semantics.
- pjmlp 5y agoTo properly compare the C standard with C++ in page count, you need to include POSIX as well. Also you should be comparing ISO standard documents editions, not books.
- tialaramex 5y agoThe argument was that C is "compact and simple". The modestly size book is both an excellent introduction and a good manual for the complete language (for C89 anyway). That's not why the language is compact and simple, it's because the language is compact and simple. In contrast Stroustrup's work is much bigger, and yet things that would later be claimed to be very important don't warrant a mention. Even assuming we accept that Bjarne is simply retrospectively imagining a motivation he never had at the time, and so these were indeed tiny inconsequential features when the book was written, somehow the "survey" of the C++ language in the much longer book is inadequate while K&R cover their entire language very well in fewer pages. Simply this is because in fact C is a "compact and simple" language. People make a lot of claims about C that I disagree with, but it certainly is simple. If I could make modest adjustments in the light of what we know now, to what was standardised in ANSI C in 1989 - a few of them would perhaps simplify it further (don't do implicit narrowing just emit a diagnostic and give up; don't try to make volatile a type qualifier) but many would make it more complicated instead (more type safety, sum-types, and of course an actual length+pointer string type) just arguably to our considerable benefit.