Yes, in fact one only has to look into what was happening during the late 50's in systems programming, starting with JOVIAL in 1958, or outside Bell Labs, to see it was indeed so.
But C is late 1960s / early 1970s, created after PL/I, Algol-68, and even Pascal.
Sadly, C went forth not only with hard-to-parse syntax, but also with stuff like undefined behavior, null-terminated strings, unchecked pointer arithmetic for array access, etc.
It was designed as a language for a confident kernel hacker working close to hardware, but ended up as a general-purpose programming language for the entire OS, and it's not the best fit for that role.
I try to always understand the current state of things in the context of how they were before the current state.
C and Unix came on to the scene - and they were much much better than what came before.
Users were meant to use the shell commands + awk and get a whole lot done with that. C programs were meant to be small. How small? Well - how much code would you be able to write using ed?
I think Unix intended for programmers to develop languages for users - use lex and yacc to come up with something to hand off to users.
The Unix operating system assumed a corporate org structure that just does not exist. Genius programmers and highly educated users.
If we went back in time to tell them how real corporations would be set up, I think C would have had safe defaults that could be disabled when needed and syntax closer to Go than C. In fact if we told them how things would be in 40 years, they would have settled on the erlang VM for stuff outside of systems and graphics programming.
C and Unix came on to the scene and they were free beer (for all pratical purposes), so they won over the other stuff that cost lots of green paper.
Had AT&T been allowed to profit from their Bell Labs research projects, and history would have been quite different, as proven when they went after Lions commentary book and BSD, shortly after been allowed again to profit from their research.
"Most people" don't matter here. The girl who bags your shopping doesn't need to know what UNIX® is for C to take over the world, but the guy who wrote Commander Keen (and who will go on to write Doom and Quake) does.
For example in Spring 1991, with Linux still just some C code Linus Torvalds was thinking of naming Freax if he got it working, JANET, the organisation providing network access to the UK's universities (via X.25 of course) decides to launch JIPS, an experimental IP network.
JIPS was huge. Why was JIPS huge? Because unlike X.25 you could just download BSD source spin up a Unix with TCP/IP and run everything you could think of or write your own software, you don't need anybody's permission - there's some guy at CERN who has written a "Web browser" which sounds pretty interesting for instance. By the time Torvalds writes his Linux 0.0.1 announcement email, JIPS is the dominant use of JANET and X.25 is on its way to deprecation.
It was all bundled together with this free software I got, 100% legit. It seems to work pretty good, and unless you've got funding from somewhere to use something different I think we should use C / IP / Unix.
I don't know about most of the people. What may have mattered was easy access to Unix for students in universities. You would normally expect there some VAXen, Sun hardware, and even PDPs, all running Unix.
Had AT&T made Plan 9 available in equally relaxed terms, history might have gone differently, too.
University site licenses for UNIX were very inexpensive. UNIX/C was way more accessible than most competitors, and students took that experience out to the real world.
My understanding of computing history is that C was basically
1. A version of PL/I that doesn’t suck. From what I can tell it was way too broad and the implementations weren’t great.
2. An Algol that is designed in the context of “represents concepts that map cleanly to lower level semantics”. Which was basically just coming full circle from Algol being a way for computer scientists to have something more expressive than Fortran and COBOL, because people kept implementing Algol and realizing that it was missing things. In my own uneducated view, Algol (and many LISPs) are too structured around the concept of completing an evaluation of a program, which made sense in the computing world when they originated, but became out of date as computers started being used for more than just directly computing things.
3. Had good implementations of several “trendy” or cutting edge concepts of the time like preprocessing, recursion, and most importantly structs. Yeah most of this wasn’t technically new. But the prior art like Algol68 was horribly flawed for other reasons.
Because the underlying system allowed concepts like null-terminated strings and unchecked pointer arithmetic, it was fair game for C. I don’t see C as a “better or worse” thing compared to other languages but something that had/has to exist as a bridge between intriguing-but-flawed/limited high level languages and the more functional but unexpressive early languages that saw adoption outside of computer science.
Of course it didn’t need to be the case that the Unix ecosystem’s userspace was mostly C, but C was a huge step up for its time. Like try reading Fortran, COBOL, Basic, and Algol and tell me you’d rather work with that than C. Pascal was later and not that much better, plus computing was a lot more fractured/expensive and the internet was basically not a thing, so it’s not like one could always just start writing pascal on their Nix or vice versa. Even today Rust and C++ are basically the only things that can replace C in many contexts, and Rust is pretty new.
> It was designed as a language for a confident kernel hacker working close to hardware, but ended up as a general-purpose programming language for the entire OS, and it's not the best fit for that role.
C is a classic case where good enough was so good that many tries at perfect couldn't unseat it.
I never felt like C was a bad tool in the 80s and at least early 90s - in many cases it was better than the alternatives which would result in slow software or would impose difficult constraints (Pascal string limits and array semantics vs. C's strings and buffers). I never thought much about C as a "kernel hacking" language because I was writing software for MS-DOS where systems programming was calling bios routines or intercepting interrupts and doing unholy things. I guess I just saw C as better than Pascal, compiled BASIC, COBOL and slow interpeted languages. When I moved to Unix, C just was the low friction way...
Hard to parse? Not in my experience. I wrote a simple C compiler while in high school using a handwritten recursive descent parser. Parsing was relatively easy, and recursive descent made generating sensible parse errors possible (vs yacc). Register tracking and allocation was the hard part.
It is comparatively hard to parse, being context sensitive (need to keep track of types) as well as requiring an implementation of the preprocessor, which has arcane enough rules that most programmers don't really know them.
Also, there are a number of historic syntax quirks that a conforming compiler, at least pre-C23, has to understand. For example, function declaration that lacks return value specification (implicit int) or parameters.
Have you actually written a C parser? I will grant that C++ is incredibly hard, but C is relatively straightforward. Types are not at all difficult to parse in C, and the pre-processor isn't all that complex either when you have the spec in front of you. If you think it's hard, you probably didn't have the right documentation. I picked up the book "The Annotated ANSI C Standard" by Herbert Schildt sometime back in ~1993, and it made writing a recursive descent parser almost trivial. That book made C syntax actually make sense in a way that the K&R book and other introductory C books didn't.
It's "hard" compared to, say, Pascal, which has a grammar that's intentionally LL(1). The fact that parsing declarators is context-dependent in particular, requiring you to maintain and consult a symbol table at that point (before you even have an AST) already to determine whether a given identifier is a type or not, is a minor annoyance, but an annoyance nevertheless.
More complex from a theory view, but not hard. You need a symbol table regardless, and symbols tables are most decidedly not "hard" to implement. Sure, it's a layering violation, but that's how we were forced to write efficient code back when computing resources were scarce 30+ years ago. An entire C compiler and integrated development environment was only a couple of hundred KB of executable on computers back in the 1980s under MS-DOS and on the Amiga.
I haven't written a C parser, but a number of other parsers. I can confidently say that C syntax, as a result of historical development, ended up in a place where it is much more annoying to parse than a properly designed language with a LL(1) syntax. If your parser can parse the following, I both congratulate you for your persistence and ridicule you for the statement that this is "not at all difficult". C syntax is annoying at the very least.
typedef struct Foo Foo;
void xx(void)
{
typedef int Bar;
Bar x;
}
void foo(int, int, int);
void bar(Foo Foo, int, int Bar);
baz(Bar, y, z)
Foo *Bar;
int y;
double z;
{
return 1;
}
I don't know what exactly is required from a conforming C compiler, but this is successfully compiled by gcc -std=c89.
The preprocessor, don't get me started. The D author, who is active on HN, has both stated that parsers are less than 0.1% of the work in a compiler, and also that the C preprocessor is terrible and he required multiple or many attempts, I think spread over multiple years, to get it right.
The way I handled it fell out as a result of how tokens were parsed. The token would be hashed, and that hash would be used to check if the token was a keyword in one hash table, then the same hash used to check in a symbol table. That made classification easy and low cost.
I don't think it's hard in practice if you use the right approach. More complex from a theory point of view, sure.
I am serious when I say that the Annotated ANSI C Standard book made this easy to understand. Without that book, parsing C types certainly did not make a lot of sense to me either. It can be found here: https://www.amazon.com/Annotated-ANSI-Standard-Programming-L...