The spiral rule works only if there is no pointer to pointer or array of array in the type. But take this for example:
+----------------------------+
| +-----------------------+ |
| | +------------------+ | |
| | | +-------------+ | | |
| | | | +--------+ | | | |
| | | | | +--+ | | | | |
| | | | | ^ | | | | | |
int * * ¦ ¦ ¦ xxx[1][2][3] | | |
^ | | | | | | | | | | |
| | | | | +-----+ | | | | |
| | | | +----------+ | | | |
| | | +---------------+ | | |
| | ---------------------+ | |
| +-------------------------+ |
+-------------------------------+
The type of xxx is a [1-element] array of [2-element] array of [3-element] array of pointer to pointer to ints. I drew a spiral that passes through each specifier in the correct order.Notice that to make the spiral correct it has to skip the pointer specifiers in the first three loops. This is marked by ¦. This is not mentioned in the original spiral rules and one could be forgiven to parse the expression as xxx -> [1] -> pointer -> [2] -> etc. following a spiral that doesn't skip the pointers.
The Right-Left Rule is quoted less frequently on HN but it's a correct algorithm for deciphering C types: http://cseweb.ucsd.edu/~ricko/rt_lt.rule.html
The spiral rule can be modified to process all array specifiers before all pointer specifiers, but then you'd have to specify that the order to do so is right and then left. At that point it's just the Right-Left Rule.
int *f();
is a function returning pointer to int, while int (*f)()
is a pointer to function returning int. Likewise, int *a[]
is an array of pointer to int, while int (*a)[]
is a pointer to array of int. *(int[])"Pointer to array of int" means you dereference it first to get an array of ints, then index to get an int.
Perhaps, but the spiral rule is one of the most complicated parts of C. Most things are trivial to someone who knows how to do the thing.
* the tricky part is that `()` are also used to denote functions. So yeah, it's not always readable. `(*)()` would be a pointer to a function returning int (the default type) and taking an unspecified amount of arguments.
EDIT: Uh, apparently you can add parens to casts but not declarations.
This doesn't compile:
int (*) p = (int *)&i;
This does: int *p = (int (*))&i
I can't quite justify this behaviour. int **p[123]; // p is array(123) of pointer to pointer to int
int *(*p)[123]; // p is a pointer to array(123) of pointer to int
Sometimes people find casts confusing because there is no identifier inside. But you can easily read it if you know where the identifier would be in an equivalent declaration.Precedence is usually documented in a man page called operator. http://man.openbsd.org/operator
You can in fact have parentheses in declarations, but the identifier must be on the inside, not just to the right of everything: https://godbolt.org/z/vKzcYMdvK
The cast says "treat this int* as an array of int*, then the first dereference says "give me the first element of that array", which gets you back the original int*.
"We start with a pointer-to-int called "a", take pointer to it and name it "p" (it's a pointer-to-pointer-to-int, although we store it in a pointer-to-whatever variable), then cast it to some weird type, dereference it thrice and store 1 into the resulting target. Two questions remain: a) what is that weird type? b) we have two levels of indirection but three dereferences, how does it work? The answer to the first question is that weird type is "pointer-to-array-of-pointers-to-int", and it helps us to answer the second question: dereferencing a value of that type is a no-op in arithmetical sense (but has a type-casting effect)."
Also, because this array type is incomplete (it has no size), I don't think you could use it in any context where it didn't "decay" into a pointer to its first element (you can test what your compiler says if you try to measure the array's size with the sizeof operator when only using one dereference).
Interpret p as a pointer to an array of pointers to integer. Since arrays decay to pointers, you triple dereference it to get
1. the array
2. the first element of that array
3. whatever int that element is pointing to
Then set it to 1.
It took me about 5 seconds. I have no idea what that Zig is supposed to do on the other hand.
Note: the programmer who wrote that C code was being very obtuse. This is essentially just `*a = 1`, the whole p thing is some form of baroque code.