Intuitive Understanding of C Declaration

Useful "Right-Left" rule for deciphering complex declaration in C programming language

Last updated Mar 3, 2021   •   5 min read   •   110 views     •  Tutorial

Contents [Show]

Overview

This article describes several examples of declaration in C programming considering the order of symbols, identifiers and explaining with an intuitive understanding.

For instance, converting this declaration

c
int (*(*func_ptr)(char *,double))[9][20];

to plain text English

func_ptr is pointer to function expecting (char *,double) and returning pointer to array (size 9) of array (size 20) of int.

Prerequisite

  • Basic understanding of programming language

An understanding of C programming language syntax, data type, identifier and the concept of pointers is advantageous, but not required.

The “Right-Left” rule Intuition

First and foremost, these symbols in C are important: asterisk*“, squared bracket[]”, and parenthesis()“.

Later, these can be useful to determine the correct declaration by using their translated English interpretation and their position in the declaration sentence.

SymbolInterpretationPosition
*as "pointer to"on the left side
[]as "array of"on the right side
()as "function returning"on the right side
These symbols can be interpreted in plain English whose position can also be interpreted to order all symbols

Step 1 – Find the Identifier

Take int *p[]; as a basic example which can be interpreted straight forward by looking from the previous Symbol-English translation table and is an array of pointers to data type int.

c
int *p[];
     ^

Here the Identifier is p and is simply intepreted as ”p is“.

NOTE: Identifier is a user-defined name/term and must not belong to keywords (pre-defined, reserved words).

Step 2 – Read all symbols to the right

Next, continue with symbols on the right of the Identifier until there is no symbol remaining OR encountering a right parenthesis.

From the Symbol-English table, the ”[]” appended after the Identifier is interpreted as “Identifier is array of” or in the case of ”()” is “Identifier is function returning”.

c
int *p[];
      ^^

Here the squared bracket is [] encountered and can be intepreted as “p is array of“.

NOTE: A special case of multiple left parenthesis with nesting between the initial parentheses only means that the whole procedure is repeated.

Step 3 – Read all symbols to the left and then the data type

Once there is no symbol on the right, moving towards the data type starting at the Identifier, i.e. left direction, until there is no symbol remaining OR encountering a left parenthesis.

c
int *p[];
    ^

Here the asterisk is * encountered and can be intepreted as “p is array of pointer to“.

Lastly, if there is no symbol belong to the Symbol-English table left, evaluate the data type.

c
int *p[];
^^^

Here the data type is int encountered and can be intepreted as “p is array of pointer to int“.

Nested Declaration

Now using int *(*func())(); for declaration to address the nesting as previously mentioned.

c
// Step 1 - Find the Identifier
int *(*func())();
       ^^^^
// "func is"

// Step 2 - Read all symbols to the right
int *(*func())();
           ^^
// "func is" 
// found "()", appending "function returning"

// Step 3 - Encounter right parenthesis, 
// read all symbols to the left
int *(*func())();
      ^
// "func is function returning" 
// found "*", appending "pointer to"

// Step 4 - Encounter left parenthesis, 
// return to read all symbols to the right
int *(*func())();
              ^^
// "func is function returning pointer to"
// found "()", appending "function returning"

// Step 5 - No remaining symbols on the right, 
// return to read all symbols to the left
int *(*func())();
    ^
// "func is function returning pointer to function returning"
// found "*", appending "pointer to"

// Step 6 - Finally, no remaining symbols on either sides, 
// evaluate data type
int *(*func())();
^^^
// "func is function returning pointer to function returning pointer to"
// found data type, appending "int".

The final result is “func is function returning pointer to function returning pointer to int”.

Illegal Declaration

Although not required upto this, knowledge of legal C declaration is necessary to avoid making illegal declaration eventhough they made sense in English-like interpretation.

PairsIllegal combinationsCorrect intepretation
[ ]( )an array of functionsan array of pointers to functions
( )( )a function returns a functiona function returns a pointer to a function
( )[ ]a function returns an arraya function returns a pointer to an array
Interprete English-like declaration also required to make proper and valid declaration based on the C programming syntax

Take the first example from this article, strip down argument list and array size, and modify it as int *((*func_ptr)())[][];. Now this is interpreted as

c
func_ptr is pointer to function returning array of array of
                       ^^^^^^^^^^^^^^^^^^^^^^^^
pointer to int

This will cause error thrown despite made sense following the Right-Left rule, because technically a function cannot return an array, but rather the pointer to that array.

Acknowledgement

This tutorial is heavily influenced by Lecture Notes created by Mr. Rick Ord from the Computer Science and Engineering Department, UC San Diego in California, USA.

Share via
Tin Nguyen

Tin “Winston” Nguyen is a Junior Embedded Software Engineer with focuses on autonomous driving, robotics, technological advancement. This blog contains news, tutorials, portfolios with demonstrated skill sets for potentially interested employer.