8 ms·
It's hard to over-estimate the historical importance of C, and the amount of groundbreaking work and important knowledge codified in C codebases. Also, it can'
by rvense 10y ago
It's hard to over-estimate the historical importance of C, and the amount of groundbreaking work and important knowledge codified in C codebases.
Also, it can't be denied that there will always be areas where the exact control of memory layout that C gives you is not just nice-to-have for performance reasons, but a prerequisite for a good implementation or understanding of some algorithm.
Neither of those points, however, mean that C is the only suitable language imaginable for doing low-level work, or that the past forty years of programming language research are irrelevant to the spaces that C excels in. I think Rust shows quite succintly the immense value of the combination of an expressive type system and C-like zero-overhead abstractions.
Learning C, like learning some assembly languages, to some extent is probably necessary if you're serious about understanding computers, just to understand what's going on. But when it comes to actual use in production systems, I am glad that we are seeing serious alternatives to a language so prone to simple bugs as C. Think of all the time and money that have been lost to buffer overflows and segmentation faults.
- bluetomcat 10y agoThe huge advantage of C (before the advent of LLVM) was that it was relatively straightforward to write a C compiler for any exotic or not-so-exotic system, since the language has very simple semantics and many operations would correspond to single machine instructions. There are literally hundreds of production C compilers written to this day. The syntax of the language is also designed to help the compiler writer and not the user – think of "declarations mirror use", the irrelevance of the order of type specifiers, etc.
- kevinnk 10y ago> The syntax of the language is also designed to help the compiler writer and not the user – think of "declarations mirror use", the irrelevance of the order of type specifiers, etc. Err, I would agree with the statement that the syntax of C (mostly) favors the compiler writer, but "declarations mirror use" is decidedly not a good example for a couple of reasons: 1. The grammar for type declarations is actually quite complicated[1] 2. Agol, which inspired C's type system, actually had a much more "compiler friendly" type syntax[2]. C's syntax is designed to be more programmer friendly. 3. Dennis Ritchie makes it pretty clear that "declarations mirror use" was intended to make use and declarations visually similar, which implies that it was done for the benefit for the programmer[3]. [1] Compare https://www.lysator.liu.se/c/ANSI-C-grammar-y.html https://www.lysator.liu.se/c/ANSI-C-grammar-y.html to [2]. [2] http://www.csci.csusb.edu/dick/samples/algol60.syntax.html#5.%20Declarations http://www.csci.csusb.edu/dick/samples/algol60.syntax.html#5... [3] "Analogical reasoning led to a declaration syntax for names mirroring that of the expression syntax in which the names typically appear...In all these cases the declaration of a variable resembles its usage in an expression whose type is the one named at the head of the declaration." from http://www.jslint.com/chistory.html http://www.jslint.com/chistory.html
- bluetomcat 10y agoThe declarator looks complex because of differences in the precedence and associativity between the asterisk, `[]` and `()` operators. The point is that the language uses a set of the same operators with the same precedence and associativity both in declarations and in normal expressions. In my view, a "user-oriented" declaration of an array of pointers would look like `pointer[10] of int`, and not `int *arr[10]`.
- barrkel 10y agoI'm guessing you mean `array[10] of pointer to int`. This is pretty close to Pascal syntax already: `array[0..9] of ^Integer`, where ^ is pronounced 'pointer to'. Pascal is a language that is genuinely easy to parse; it's designed to be LL(1). C is not; in particular, typedefs effectively introduce keywords, and the easiest way to parse C is to inform the tokenizer about typedefs as they're found so the parser can disambiguate things like `a (b);`; this looks simultaneously like declaring a variable and calling a function, depending on the type of 'a'.
- Roboprog 10y agoMaybe I'm missing something, but I think Pascal "TYPE" blocks and C "typedef" statements do pretty much the same thing. (they don't look the same, but you can use either to define record/structure types or enums, for example)
- barrkel 10y agoThe distinction is in the syntax. int main() { foo(bar); foo * bar; } If foo is a typedef, these are variable declarations, otherwise the first is a function call and the second multiplication (syntactically). These are different kinds of things that would normally be up to the parser to figure out (rather than semantic analysis later). These are well-known ambiguities relating to typedefs in C (well-known to compiler authors, at any rate). The situation doesn't come up in Pascal because variables go in the var block (starting with the 'var' keyword) and functions and procedures both start with keywords ('function' and 'procedure').
- Tomte 10y agoBut C doesn't give you "exact control of memory layout". Bit-fields, structs, virtually everything except arrays has implementation-defined or unspecified memory layout. If you look at another old language, Ada, you'll find much more precise control.
- bluetomcat 10y agoC11 has `_Alignas(...)`, which works both with a size or a type. Before that, compiler-specific alignment attributes could be used, for example, GCC's `__attribute__((aligned(...)))`.
- rubber_duck 10y ago>implementation-defined In theory that's important, in practice you rely on implementation-defined behavior and put it behind a layer of macros. It's not perfect but it works - low level capabilities are not the problem in C. Lack of high level abstractions make scaling it up and maintaining a PITA.
- planteen 10y agoThat's true but at the end of the day it's fine as long as you aren't using those constructs for serialization/deserialization of data between machines. Rob Pike has a very good post about how Plan 9 needed no endian specific #defines: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html?m=1 https://commandcenter.blogspot.com/2012/04/byte-order-fallac...
- S_I 10y agoAs much as the Rust community does right with respect to the technical aspects of the language, as much they still don't (seem) to understand the non technical problems it has. Do you know which non technical advantage C has? Multiple implementations. Don't like gcc, use clang. The Keil compiler has a certain bug that screws your project? Use IAR. And so on. That is one thing. Another thing (at least at the company i work for and the ones i know) is, companies that write code for infrastructure or machines that need to rung a looong time won't ever trust a language (and toolchain) that comes in versions and not in IEEE standards. That may or not be stupid, but it is the reality i've seen so far. P.S.: Before someone says C only NOW has multiple implementations, yes, at some point in time that was true, but i was VERY easy for compiler vendors to implement a C compiler (speak ROI). Time will tell if this will be true for Rust as well.
- Manishearth 10y ago> companies that write code for infrastructure or machines that need to rung a looong time won't ever trust a language (and toolchain) that comes in versions and not in IEEE standards The Rust team has a very high commitment to stability, and does way more to maintain stability than any other language/compiler I know of (by testing new versions and potentially-breaking-changes against the entire ecosystem) > still don't (seem) to understand the non technical problems it has. Just because multiple implementations of Rust don't exist (there are a couple but nothing 100% feature complete iirc) doesn't mean that the community doesn't understand the need for it. Alternate implementations are hard to write and take time. The language is still new, but work is being done towards speccing it (e.g. the unsafe code semantics work being done right now). Note that most languages have gone for years without getting a proper spec or alternate implementations. This is an advantage C has over Rust, agreed. It's usually not a dealbreaker, though.
- S_I 10y ago>The Rust team has a very high commitment to stability, and does way more to maintain stability than any other language/compiler I know of (by testing new versions and potentially-breaking-changes against the entire ecosystem) Yes, but my experience is that they don't seem to manage generating the kind of trust needed to get my peers to give it a serious go. It's a purely social and subjective problem. >Just because multiple implementations of Rust don't exist (there are a couple but nothing 100% feature complete iirc) doesn't mean that the community doesn't understand the need for it. As i said, it SEEMS to be so. That means that it is a subjective impression my colleagues and me get. It is the job of the community to generate trust, not the (potential) user's. >Alternate implementations are hard to write and take time. Yes, see my P.S. Time will tell if it's worth it to compiler vendors. C made it easy for them right from the start. >Note that most languages have gone for years without getting a proper spec or alternate implementations. This is an advantage C has over Rust, agreed. It's usually not a dealbreaker, though. Not a dealbreaker for whom? In the infrastructure and big machine business you will see C, some C++ and Ada. All standardized. If the Rust community wants to offer an alternative for C, C++ and Ada, AND want Rust to succeed as an alternative, they need to understand that trust (in the toolchain) is generated in different ways in different industries.