Who invents a language that needs such a complicated rule to read variable declarations? (This is a rhetorical question. We all know who invented C.) The fact that it’s consistent and logical doesn’t make it simple. Human language doesn’t generally read clockwise. Left-to-right or right-to-left, sure, but not clockwise.
As you say, this is a general rule with some exceptions. :)
On a related note…not left-to-right or right-to-left, but left-to-right and right-to-left.
I think I remember hearing somewhere that K&R later came to the conclusion that making the unary (*) operator go on the left instead of on the right was a mistake, but one whose consequences didn’t really become clear until after the grammar was already effectively fixed. I’m not confident in the veracity of that.
I can’t personally imagine the machines on which early C programs ran being able to fit enough code to make pointers to functions that take and return other pointers to functions be something that one would see very often?
The fact that it’s consistent and logical doesn’t make it simple
Agreed. I think “C pointers” is such a complex subject for so many people (how many other languages have books written just about their pointer handling alone - I can’t think of another), but the majority of that is caused by the syntax rather than the concepts themselves. I used and understood pointers just fine in other languages (including x86 assembly language) but the syntax tripped me up for a long time when I started programming in C - the simple cases are fine, it’s the more complex nested cases that did me in.
If a declaration is complicated enough that you don’t want to parse it in your head, you can just use the command-line tool cdecl or its online version http://cdecl.org/. It converts “C gibberish ↔ English”. (That’s right, it converts both ways.)
For instance, example #2 in the article is char *(*fp)( int, float *);. After reading in spiral order, the article shows that you can understand the declaration as “fp is a pointer to a function passing an int and a pointer to float returning a pointer to a char”. But if you just paste that declaration into cdecl, it tells you the same thing: that line will “declare fp as pointer to function (int, pointer to float) returning pointer to char”.
char *(*fp)( int, float *);
I’ve always preferred the right-left rule.