Deciphering Intricate Declarations Of C: The Concept Of C Declarators

The set of statements that one can write as part of defining the block that constitutes the body of any function written in C falls broadly into two categories:

  1. Declarative statements and
  2. Executable statements

In this article, I have considered explaining only declarative statements. They are used to declare:

  1. Simple variables or constants, like int x: or const double PI = 3.14
  2. Pointers, like int *p or const int *q
  3. Arrays, like int a[10]
  4. Functions, like int factorial (int n);

Anyone who has at least covered a primer on C is familiar with the meanings of these declarations. It seems like there’s nothing much to learn but it’s quite the opposite. Most of the students who are exposed to the language of C just study it for either they have to pass a semester exam or try some competitive coding platform to solve a few data structure and algorithm-related questions: none of these does consider writing some serious software in C.

Why Other Programming Languages Are Commonly Used Over C?

Most of us pursue some other language like Java, JavaScript or Python for the development of software in future. Do we learn advanced parts of speech of these languages but not C. Why? Because the practical area of software development where C is used is not meant for some ordinary developers.

C is used to develop operating systems kernel, low-level device drivers, high-speed routing protocols, language runtime for other languages etc. Alas most of us are only interested in developing some superficial desktop or web applications and hardly have time for paying heed to the core computer science topics.

Long ago while studying Linux system programming (Beginning Linux Programming, 4th edition: Neil Matthew and Richard Stones) I came across the prototype of the signal handling function:

#include <signal.h>

void (*signal(int sig, void (*func)(int)))(int);

Can you dissect the above declaration grammatically? Well, a signal is a function that takes two arguments-

  1. An integer (int sig)
  2. A pointer to a function (void (*func)(int))

Let’s dissect the function pointer argument itself: void (*func)(int). It’s a pointer to a function that receives an integer argument and returns nothing i.e., void.

Tricks To Dissolve A Complex Declaration:

Now the question arises: what’s the return type of the function ‘signal’? It’s the same function pointer that the signal has received. You are wondering exactly how I came to such a conclusion? Well, I have a few tricks at my disposal when I’m asked to dissolve a complex declaration in C.

Let me discuss those tricks in this blog.

Whenever I try to untangle the meaning of any declaration at first, I rank the declarators from higher to lower as follows:

[table id=3 /]

Now if you want to analyze the above declaration of the signal function then first underline it as follows:

Tricks To Dissolve A Complex Declaration

Look, I’ve numbered the sections by the precedence and associativity of the declarators. So, if you want to analyze what’s signal then you have to get inside section 1 first. Let’s analyze now section 1.

Tricks To Dissolve A Complex DeclarationObviously, the higher precedence of the () following signal makes it a function rather than a pointer (Look at the * preceding the word signal). Now, ‘signal’ is a function. If you want to dissect further about any function then ask yourself the following two questions:

  1. What are its arguments or their types?
  2. What about its return type?

Well, let’s try to answer these questions. To answer the first question just get inside the section number 1:

Tricks To Dissolve A Complex Declaration

What do we see here? We see two arguments here.

  1. An integer: int sig
  2. But what about this second argument?

Let’s analyze it now.

If we get inside section 1, we see that it’s a pointer. If you set your foot on a pointer while traversing various parts of a C declaration then ask yourself only one question:

  1. What kind of data does it really refer to?

Well, the answer can’t be found in section 1. If you get out of the surrounding parentheses of section 1 then you have to move to the right and not the left because the right section has more precedence than the left. You see there that it’s a function that can consume only one argument of type int.

Now you have to get out of this section if you want to know the return type of this function: it’s at the extreme left as it has the lowest precedence i.e., void. Look at the movements that I’ve made in the next diagram:

Tricks To Dissolve A Complex Declaration

Well let’s get back to the earlier diagram:

Tricks To Dissolve A Complex DeclarationCan you remember we asked ourselves two questions?

  1. What are its arguments or their types?
  2. What about its return type?

We answered only the first question. Let’s try to answer the second question.

You can’t get any knowledge about the return type inside the pair of parentheses following the function name: signal, so you have to move to the left and you see there is a * which signifies that the function returns a pointer. Now as I told you that whenever you come across a pointer when making a journey through the several parts of a C declaration ask yourself only one question:

  1. What kind of data does it really refer to?

Well, if you wanna answer this question you have to refer to the earliest diagram:

Tricks To Dissolve A Complex Declaration

The answer can’t be found inside the surrounding parentheses of section 2 so let’s get out of it. Now you have to move to the right because the right section has more precedence than the left and we see there that signal returns a pointer to a function. Once again you set your foot on a function and you are going to ask yourself the same two questions:

  1. What are its arguments or their types?
  2. What about its return type?

Now we can answer these questions quickly. The answer to the first question is that the function receives an argument of type int. But if you want to answer the second question you have to go to the extreme left: the return type of the function is void.

Just refer to the following diagram to observe the movements that I’ve made:

Tricks To Dissolve A Complex Declaration

Let’s refer to the above diagram to conclude the signal function’s prototype:
‘signal’ is a function that takes two arguments:

  1. An integer: int sig
  2. A pointer to a function that can take an int as an argument and returns nothing i.e., void

The ‘signal’ function returns a pointer to a function that takes an int as an argument and returns nothing i.e., void.

Conclusion:

Convinced? If you have any doubt you can write to me or if you have some other complex declarations that you can’t analyze yourself, just send them to me. I will try my best to analyze them and write back to you I promise.

If you wish to learn C programming language in details and wish to turn yourself into an expert, then join Webskitters Academy. Industry professionals, like me, are always on their toes to help you enhance your technical skills and walk towards a bright future!

Also Read some of our other technical blogs,

Dhruba

Dhruba Ray is an expert trainer having years of experience in disseminating proper training to aspirants. Possessing an in-depth knowledge of Data Analysis, Machine Learning and Deep Learning, he is a great enthusiast of modern and advanced technologies. He has sound knowledge in scikit learn and tensor flow and have developed several state-of-the-art CNN models from scratch and customize them for better results in image processing. His first-hand experience always works wonders for our students and their knowledge.