Understand All Declarations With The Clockwise-Spiral Rule
Updated:
The Clockwise-Spiral Rule is a must-have tool that lets C/C++ programmers quickly understand the meaning of variable or function declarations. Let’s see right now how to use it.
3 Steps to understanding
-
Starting from the identifier you want to decode, move in a spiral / clockwise direction. Also, resolve anything in parenthesis first.
-
Replace these elements with the following statements:
[N]or[]→N-elements array of… or, array of undefined size of…(type_1, type_2)→ function passingtype_1andtype_2…*→ pointer to…
-
Repeat 1-2 until all tokens are processed.
Decoding a simple declaration
Let’s try to decode this simple statement to get started.
float *samples[N_SAM];
Let’s apply the Clockwise-Spiral Rule and proceed step by step.
___________________
| ________ |
| | ↓ |
float *samples[N_SAM]; |
↑ ↑ | |
| ‾‾‾‾‾‾‾‾‾‾‾‾ |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
- Let’s start with the identifier:
samplesis…
- Let’s process
[N_SAM]:
samplesis anN_SAM-elements array of…
- Let’s process
*:
samplesis anN_SAM-elements array of pointers to…
- Let’s process
float:
samplesis anN_SAM-elements array of pointers to float!
The classic Hamlet doubt
When you can’t remember the difference between “const type*” and “type* const”, the Clockwise-Spiral Rule is the only thing that can save you if you can’t google!
const char* pcc;
Let’s build with the spiral path:
_______________
| ___________ |
| | ______ | |
| | | | | |
const char* pcc; | | |
↑ ↑ ↑ | | |
| | ‾‾‾‾‾‾‾‾‾ | |
| ‾‾‾‾‾‾‾‾‾‾‾‾‾ |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
We can easily see that the former declaration corresponds to the statement:
pccis a pointer to acharconstat
Similarly we can also decode the alternative version:
char* const cpc;
And we get:
cpcis a constant pointer to achar
A headache-level declaration
Here is the POIX signal function.
void (*signal(int, void (*handler)(int)))(int);
Trying to figure out what the hell signal is can give you a headache quickly. So, let’s try with the Clockwise-Spiral Rule!
______________________________________
| ____________ |
| _______ | _____ | |
| | ↓ | | | ↓ ↓
void (*signal(int, void (*handler)(int)))(int);
↑ ↑ | ↑ ↑ | | |
| ‾‾‾‾‾‾‾‾‾‾ | ‾‾‾‾‾‾‾‾‾ | |
| ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
- First we see that
signalis a function because the name is followed by(:
signalis a function passing anintand a…
-
At this point we find
handlerin parentheses, so we have to solve it for a moment alone.- Since the
handleridentifier is followed by a closing parenthesis we go directly to*:
handleris a pointer to…- Go on and we get
(int), so:
handleris a pointer to a function passing int…- Now go ahead and see the
voidreturn type:
handleris a pointer to a function passing int and returning void. - Since the
-
We’re done with
handler, so let’s pick up withsignal:
signalis a function passing anintand a pointer to a function passing int and returning void…
- In this moment we have to complete this path to
*:
_______
| ↓
void (*signal(int, void (*handler)(int)))(int);
↑ |
‾‾‾‾‾‾‾‾‾‾
signalis a function passing anintand a pointer to a function passing int and returning void, returning a pointer to…
- Go on with the path and reach
(int):
______________________________________
| _______ |
| | ↓ ↓
void (*signal(int, void (*handler)(int)))(int);
↑ |
‾‾‾‾‾‾‾‾‾‾
signalis a function passing anintand a pointer to a function passing int and returning void, returning a pointer to a function passingint…
- Complete the spiral with
void, which is the last token:
______________________________________
| _______ |
| | ↓ ↓
void (*signal(int, void (*handler)(int)))(int);
↑ ↑ | |
| ‾‾‾‾‾‾‾‾‾‾ |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
signalis a function passing anintand a pointer to a function passing int and returning void, returning a pointer to a function passingintand returning void
Easy, isn’t it?