Plus the fact that arrays in type names sometimes act as pointers and sometimes not.
The best shot is to name intermediate types, since they aren’t really intermediate most of the times. Properly structured programs tend to disassemble complex structures to work on them, so you need these names anyway.
That said, C compilers definitely lack -Wunreadable-types flag which must be default.
It is a widely accepted practice to typedef pointers to functions.
With pointers, more than 2 levels of indirection is an indication of a badly written program.
In practice, the most complex declarations you should write are "pointer to pointer to x", "array of pointers to x", "array of function pointers returning x". Stuff like "pointer to function returning pointer to pointer to array" is nonsensical most of the time.
Foo : array (Positive range 1 .. 100) of access function return access Integer; uggclang: error in integer literal, did you mean "ONE HUNDRED"? at line oneAll syntax is horrible. Rust is the en vogue tool of the moment and it's objectively harder to read than C. Python used to be clean and now it's sort of a mess. C++, well...
Some languages try to get away with having simple syntax though. Javascript is in this camp, as of course are all the Lisps. And the result is that you end up drowning in a sea of complicated semantics instead, c.f. the famous "wat" video or the fact that every sexpr macro-ized DSL works like its own little butterfly.
You can't win. C is fine. Could you do better if you started from scratch? Sure. Would it last? No.
I think you're just used to C syntax. I find Rust syntax much easier to read than C syntax (and that was already true when I didn't know either language well).
rust surely has it's issues, but reading types is not one of them. whatever you put inside the <> of a outermost symbol is a straightforward tree parse.
C type syntax has a simple guiding principle, there is no type syntax and "declaration follows usage" i.e. normal expression syntax. A few ugly additions that don't cleanly fit in this model were made later for practical reasons, but they don't change the basic idea, which is that there is so little to C type syntax that you can barely see it (which may also be why it's so easy to read once you've grokked it).
When you have an entire Wikipedia article dedicated to how infamously hard your language is to parse, you have no choice but to admit that you've messed up: https://en.wikipedia.org/wiki/Lexer_hack
And let's not forget: https://en.wikipedia.org/wiki/Dangling_else
C++ must be comparatively a lot harder to parse -- C++ syntax is a huge amount of complexity added to a system that wasn't designed with that in mind.
That you link "Dangling else" is curious. The wikipedia page talks about "ambiguity" but in my mind it's no different than the ambiguity in "a + b * c", does it mean "(a + b) * c" or "a + (b * c)"? Well, make a choice and write it down.
Or don't and don't allow unnecessary ambiguity. For * and +, there's a agreed upon order of operations far more universal than a programming language, but it's sensible to use a partial order so nobody is mistaken about whether e.g. logical or and bitshift binds tighter. Similary C counld have just not have allowed omitting the braces around single-line else clauses and would have been a simpler language for it.
So... we collectively made a choice and wrote it down, then? I think you whooshed on the point. The if/else ambiguity is just a precedence rule, like many others in the expression grammar of every (well, every non-lisp) language that exists.
Which is a flaw that other languages don't have to deal with, because they learned from C's mistakes. There's no justifiable reason for a language's grammar to make this sort of thing necessary. C would be better--and simpler--without it.
I would like to have a better syntax too but it's a tradeoff. I really want to like more algebraic syntaxes like Zig/Odin/Jai but C's terseness and ease of use for the common, simple cases is unmatched unfortunately.
If this is "objectively" true please link the study which was able to somehow measure that.
That said, C's syntactic missteps appear to be accidents, while Rust delights itself in being ugly.
Rust has an innovative, but highly opinionated, memory model: the premise is writing high performance memory safe programs, with 'zero cost' abstractions and so on. You might write a program in Rust rather than C in the way you might write a program in Go rather than C: because the application is better modeled in a language which isn't C. For programs which pertain to the domain where C should be considered on its merits, if you try to write them in Rust, you may as well start each module with an unsafe block.
But no, C is not fine. It has a stunning amount of own-goals making it pointlessly difficult to write a program with a fine-grained memory policy that is correct. C also doesn't have a syntax at all until you've run CPP, and then you have a context-sensitive parse. Neither of these are mere technical formalities, they actively inhibit understanding a C program.
This is often said, but does not reflect reality. At this point, we have tons of bare-metal and OS-level Rust code existing in the world, and it still has very little unsafe overall.
There are many programs one can write in C, or Zig, or some other manual-transmission language, which, if you wrote them in Rust, would just be wrapped in a big unsafe block. That isn't because those programs have memory errors in them, it's because they have a memory policy which safe Rust doesn't support.
Examples include certain garbage collection algorithms, and embedded programs where all memory is pre-allocated and references shared somewhat promiscuously. It's possible to write analogous programs in safe Rust, but not the same program. The space of programs which are both correct, and not possible in safe Rust, is infinite. They don't come with compiler guarantees, so other support is needed. CompCert is a good example of an approach to that which isn't Rust's.
Keeping in mind that I'm referring to specific programs, not "a program which solves the problem domain". Otherwise we could just say that since you can write a program which solves the problem domain in Python, there's no use for Rust. That wouldn't lead to a productive conversation, would it.
People still choose C over Rust, even knowing what Rust is. This isn't the early days of the evangelism strike force, Steve. The above is why.
Sometimes they might be better off writing the analogous program in Rust, or seeing if they can get the program they're trying to write with limited use of unsafe blocks. Sometimes not. I know you've put a lot of work into your hammer over the years, but it's never going to be the only tool in the box.
Languages, and I'm thinking of Zig here, which make it easier to correctly implement a memory policy which doesn't happen to be Rust's, should be applauded, and not called "a massive step backwards for the industry <pouty sad face>". Like it or not, they're working in the same domain as Rust, based on different principles.
But yes, there is an infinitely large class of programs which can be written in the embedded and OS spaces, in Rust, with very little unsafe overall. I didn't intend to imply otherwise.