Declaration VS Definition: What's The Difference
Updated:
In C and C ++, we must understand the difference between declaration and definition. Studying these languages, we often hear about them. They are two fundamental aspects that, if not understood, can lead to annoying errors such as “undefined reference to …“ or to problems of “implicit definition of …“.
TL;DR
- A declaration is just about informing the compiler that a variable or a function exists, with that name and of that type.
- A definition is where the storage gets actually allocated for variables and where the functions get implemented.
- You can have many declarations of the same thing, but only one definition.
Declaring things
The declaration only provides the compiler with fundamental attributes of a variable or function, basically just the type and its identifier (its name). A declaration is helpful to explain to the compiler how to handle references to that identifier. It’s what the compiler needs to handle those references.
extern int ival;
extern char buf[];
int foo(float x);
A declaration does not actually implement that identifier. It just informs the compiler, for example, that there exists somewhere a variable ival of type int and a function called foo that needs a float as input and returns an int as output. We stress the purely informative nature of a declaration.
It is worth noting that the only way to declare a variable in C without defining it is by using the extern keyword. It is the only way not to physically dedicate a portion of memory for that variable, suggesting that other code somewhere else handles this aspect.
Modularization
C is a language that allows a modular design of your program. Declarations deal with visibility, so we can use them to create an interface between these modules, allowing the various parts of the codebase to connect smoothly. All this wiring thing is why header files are a bit like buckets full of declarations. But we talk about this and how to modularize a program properly in another Dev Tip.
It’s time to define those things
A definition instantiates or implements that identifier. Now the focus is on the linker and no longer on the compiler. The linker uses the definition to correctly link all the references of an identifier to its actual implementation. If this identifier is a variable, the linker will work on the location of that memory location, but if it is a block of code, its job is to address it correctly when a function call occurs.
int ival;
char buf[100];
int foo(float x) {
return floor(6.28 * x);
}
This is an example of the definition of what we declared earlier. Now we instantiate the actual memory for the variables and implement the foo function’s body.
A few things to remember
It is not mandatory to have a declaration. A definition also gives us visibility of that identifier in its scope. So when we have just a definition without a declaration, we talk about defining declaration.
Also, an identifier can be declared as many times as you want. Since it’s only a matter of providing information about the characteristics of an identifier, it’s not a problem to repeat the same declaration.
Conversely, there must be exactly one definition of an identifier and just one. If you forget to define something that is declared and referred to somewhere else, the linker laments about missing symbols. On the other hand, if you define the same identifier more than once, the linker no longer knows which implementation to use and complains about duplicate symbols.