The C ``Clockwise/Spiral Rule''
Decoding C: The "Clockwise/Spiral Rule"
Originally shared by David Anderson on comp.lang.c (1994-05-06), the Clockwise/Spiral Rule is a mental framework that allows any C developer to decipher even the most convoluted declarations.
🌀 The Methodology
To parse a declaration, you must read it linearly from left to right follow a spiral path. Start at the identifier (the variable name) and move in a clockwise direction.
The Translation Key
Whenever you encounter specific symbols, replace them with these English phrases:
| Symbol | English Translation |
|---|---|
[X] or [] | "Array of size X..." |
(type1, type2) | "Function taking type1 and type2, returning..." |
* | "Pointer to..." |
The Execution Process
- Identify the unknown element (the variable name).
- Move clockwise/spirally from that point.
- Substitute symbols using the table above.
- Repeat until every token in the statement has been visited.
🛠️ Practical Examples
Example #1: The Basics
Consider the following line of code:
char *str[10];
The Question: What exactly is
str?
- Start at
str. Moving clockwise, we hit[. str is an array of 10... - Continue the spiral to find
*. ...pointers to... - Reach the end of the line (
;), then wrap around to the start to findchar. ...char.
Final Result: str is an array of 10 pointers to char.
Example #2: Function Pointers
Now, let's look at something more complex:
char *(*fp)( int, float *);
The Question: What is
fp?
- Step 1: Start at
fp. It is enclosed in parentheses(), so we resolve the inside first. We see*. fp is a pointer to... - Step 2: Exit the parentheses and move clockwise to
(. ...a function taking anintand a pointer tofloat, returning... - Step 3: Continue the spiral to find
*. ...a pointer to... - Step 4: Wrap around to the beginning to find
char. ...char.
Final Result: fp is a pointer to a function passing an int and a pointer to float returning a pointer to a char.
Example #3: The "Ultimate" Challenge
This is the peak of C declaration complexity:
void (*signal(int, void (*fp)(int)))(int);
The Question: What is
signal?
Because signal is inside parentheses, we must resolve the nested elements first.
- Look at
fp: It's inside parentheses with a*, followed by(int), returningvoid. fp is a pointer to a function passing an int returning nothing (void). - Now back to
signal: It is a function passing anintand thefpwe just defined, returning... - We are still in the inner parentheses and see
*. ...a pointer to... - Move clockwise to the next
(int). ...a function passing an int returning... - Finally, we hit the outermost
void.
Final Result: signal is a function passing an int and a pointer to a function passing an int returning nothing (void), returning a pointer to a function passing an int returning nothing (void).
⚖️ Qualifiers: const and volatile
The same spiral logic applies to type qualifiers. Let's test it:
Case A: char * const chptr;
- Start at
chptrconst*char. - Result:
chptris a constant pointer to char.
Case B: volatile char * const chptr;
- Start at
chptrconst*volatile char. - Result:
chptris a constant pointer to a volatile char.
📚 Further Study
To master this technique, practice with the exercises found in K&R II, page 122.
Copyright 1993, 1994 David Anderson This material may be distributed freely provided the author's name and this copyright notice remain intact.