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

  1. Starting from the identifier you want to decode, move in a spiral / clockwise direction. Also, resolve anything in parenthesis first.

  2. Replace these elements with the following statements:

    • [N] or [] → N-elements array of… or, array of undefined size of…
    • (type_1, type_2) → function passing type_1 and type_2…
    • * → pointer to…
  3. 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:

samples is…

  • Let’s process [N_SAM]:

samples is an N_SAM-elements array of…

  • Let’s process *:

samples is an N_SAM-elements array of pointers to…

  • Let’s process float:

samples is an N_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:

pcc is a pointer to a char constat

Similarly we can also decode the alternative version:

char* const cpc;

And we get:

cpc is a constant pointer to a char

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 signal is a function because the name is followed by (:

signal is a function passing an int and a…

  • At this point we find handler in parentheses, so we have to solve it for a moment alone.

    • Since the handler identifier is followed by a closing parenthesis we go directly to *:

    handler is a pointer to…

    • Go on and we get (int), so:

    handler is a pointer to a function passing int…

    • Now go ahead and see the void return type:

    handler is a pointer to a function passing int and returning void.

  • We’re done with handler, so let’s pick up with signal:

signal is a function passing an int and 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);
      ↑        |  
      ‾‾‾‾‾‾‾‾‾‾   

signal is a function passing an int and 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);
      ↑        |  
      ‾‾‾‾‾‾‾‾‾‾   

signal is a function passing an int and a pointer to a function passing int and returning void, returning a pointer to a function passing int…

  • Complete the spiral with void, which is the last token:
      ______________________________________
      |  _______                           |
      |  |     ↓                           ↓ 
void (*signal(int, void (*handler)(int)))(int);
 ↑    ↑        |                           |
 |    ‾‾‾‾‾‾‾‾‾‾                           | 
 ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾

signal is a function passing an int and a pointer to a function passing int and returning void, returning a pointer to a function passing int and returning void

Easy, isn’t it?