Declarations and Their Syntax in C
Declarations play a fundamental role in the C language. By declaring a variable or a function, essential information is provided to the compiler which can use it to check potential errors and to generate more efficient code.
In previous lessons we have seen examples of variable and function declarations but without going into too much detail. Starting from this lesson, we will see declarations and their syntax in more detail.
We will use the concepts of this lesson as a starting point to then tackle more advanced concepts such as storage classes and type qualifiers.
Declaration Syntax
A declaration in C language can be seen as a non-executable statement that provides information to the compiler regarding a particular identifier.
For example, when we write:
float x;
we are essentially telling the compiler that, within the current scope, the name x represents a variable of type float.
Similarly, when we write for example:
int sum(int a, int b);
we are declaring a function named sum that accepts two parameters of type int and returns a value of type int.
In general, a declaration has the following form:
specifiers declarators;
Where:
specifiers, also called declaration specifiers, are a list of keywords that describe the properties of the variable or function we are declaring;declarators, also called base declarators, are a list of identifiers separated by commas. Declarators can also provide additional information about properties.
Let's analyze them separately.
Declaration Specifiers
Declaration specifiers can be divided into three types:
-
Storage Classes:
also called storage classes, they specify the lifetime and visibility of an entity.
In C Language there are five storage classes. Furthermore, only one storage class can be specified for each declaration:
autoregisterstaticexternthread_local
-
Type Qualifiers:
they specify how the value of a certain variable can change over time. There are four of them and a declaration can contain from zero to more than one:
constvolatilerestrict_Atomic
In particular, the third,
restrict, was introduced in the C99 standard, while the last,_Atomic, was introduced in the C11 standard. -
Type Specifiers:
they specify the data type of the variable or function we are declaring. There are several, including:
voidcharintfloatdoubleshortlongsignedunsigned
Furthermore, it is possible to define custom data types using structures, unions and enumerations.
Type specifiers can be combined with each other as we have already seen previously. Furthermore, the order in which they appear is not relevant, for example the declarations:
int unsigned long x; unsigned long int x;are equivalent.
Furthermore, we can also use type names specified with
typedef.
In the C99 standard a special declaration specifier has also been added that is used exclusively for functions: inline. We will explore it in upcoming lessons.
In general, type qualifiers and type specifiers must always be inserted after the storage class and before the base declarators, so the sequence becomes:
storage_class type_qualifiers type_specifiers base_declarators;
However, between type qualifiers and type specifiers, the order is not relevant.
Declarators
As for base declarators, they can be:
-
simple names: in which case we are declaring a variable;
int x;in this case the declarator is simply
x, that is the name of the variable. -
names followed by parentheses: in which case we are declaring a function;
int sum(int a, int b);in this case the declarator is
sum(int a, int b). -
names followed by square brackets: in which case we are declaring an array;
int numbers[10];in this case the declarator is
numbers[10]. -
names preceded by an asterisk: in which case we are declaring a pointer;
int *p;in this case the declarator is
*p.
In a single declaration we can have multiple declarators separated by commas:
specifiers declarator1, declarator2, ..., declaratorN;
Each individual declarator can be followed by an initializer, that is an expression that assigns an initial value to the variable. This, obviously, only applies to variables.
The general syntax is as follows:
specifiers declarator = expression;
Summary of Declaration Syntax
Let's now summarize the general syntax of declarations in C language:
Declaration Syntax in C Language
The syntax of a declaration in C language is as follows:
storage_class type_qualifiers type_specifiers declarator1, declarator2, ..., declaratorN;
Where:
-
storage_classis a storage class, that is one of the keywordsauto,register,staticorextern;The storage class can be absent or only one can appear.
-
type_qualifiersis a list of type qualifiers, that isconst,volatileorrestrict;Type qualifiers can be absent or more than one can appear.
-
type_specifiersis a list of type specifiers, that isvoid,char,int,float,double,short,long,signed,unsignedor types defined withtypedef; -
declarator1, declarator2, ..., declaratorNare base declarators, that is names of variables, functions, arrays or pointers;Declarators can be followed by an initializer except in the case of functions:
specifiers declarator1 = expression1, declarator2 = expression2, ..., declaratorN = expressionN;The initializer is an expression that assigns an initial value to the variable.
Examples
Let's put into practice the rules seen above by examining some examples.
Let's observe the following figure:
In this example we have:
- A storage class:
static; - A type specifier:
double; - Three declarators:
aandbwhich are simple variables and*pwhich is a pointer.
We have no type qualifiers.
Let's examine this second example:
In this example we have no storage class. However we have:
- A type qualifier:
const; - A type specifier:
char; - A declarator:
example[]; - An initializer:
= "Test";
In this case, example is a constant character array.
Let's analyze another example that has both storage class and type qualifier:
In this example we have:
- A storage class:
extern; - A type qualifier:
const; - Two type specifiers:
unsigned int; note that their order is irrelevant. We could also have writtenint unsigned; - A declarator:
x.
To conclude, let's examine a last example of a function declaration:
In this case we have declared a function using:
- A storage class:
extern; - A type specifier that indicates its return type:
double; - An identifier:
square(double). This identifier indicates that thesquarefunction accepts one parameter of typedouble.
In Summary
In this lesson we have explored in depth the syntax of declarations in C language. In previous lessons we had only mentioned it.
In particular we have seen that:
- A declaration is composed of specifiers and declarators;
- Specifiers can be of three types: storage classes, type qualifiers and type specifiers;
- Declarators can be names of variables, functions, arrays or pointers;
- A declaration can contain multiple declarators separated by commas;
- Each declarator can be followed by an initializer.
Although we have already studied type specifiers in previous lessons, especially when we studied data types in C, we have not, however, yet addressed the meaning and use of storage classes and type qualifiers. These topics will be covered in upcoming lessons.
In particular, in the next lesson we will address the concept of storage classes.