Take a look at this seemingly innocent sample program:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> int main() { std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n'; return 0; } int add(int x, int y) { return x + y; } |
You would expect this program to produce the result:
The sum of 3 and 4 is: 7
But in fact, it doesn’t compile at all! Visual Studio produces the following compile error:
add.cpp(5) : error C3861: 'add': identifier not found
The reason this program doesn’t compile is because the compiler compiles the contents of code files sequentially. When the compiler reaches the function call to add on line 5 of main, it doesn’t know what add is, because we haven’t defined add until line 9! That produces the error, identifier not found.
Older versions of Visual Studio would produce an additional error:
add.cpp(9) : error C2365: 'add' : redefinition; previous definition was 'formerly unknown identifier'
This is somewhat misleading, given that add wasn’t ever defined in the first place. Despite this, it’s useful to generally note that it is fairly common for a single error to produce many redundant or related errors or warnings.
Best practice
When addressing compile errors in your programs, always resolve the first error produced first and then compile again.
To fix this problem, we need to address the fact that the compiler doesn’t know what add is. There are two common ways to address the issue.
Option 1: Reorder the function definitions
One way to address the issue is to reorder the function definitions so add is defined before main:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> int add(int x, int y) { return x + y; } int main() { std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n'; return 0; } |
That way, by the time main calls add, the compiler will already know what add is. Because this is such a simple program, this change is relatively easy to do. However, in a larger program, it can be tedious trying to figure out which functions call which other functions (and in what order) so they can be declared sequentially.
Furthermore, this option is not always possible. Let’s say we’re writing a program that has two functions A and B. If function A calls function B, and function B calls function A, then there’s no way to order the functions in a way that will make the compiler happy. If you define A first, the compiler will complain it doesn’t know what B is. If you define B first, the compiler will complain that it doesn’t know what A is.
Option 2: Use a forward declaration
We can also fix this by using a forward declaration.
A forward declaration allows us to tell the compiler about the existence of an identifier before actually defining the identifier.
In the case of functions, this allows us to tell the compiler about the existence of a function before we define the function’s body. This way, when the compiler encounters a call to the function, it’ll understand that we’re making a function call, and can check to ensure we’re calling the function correctly, even if it doesn’t yet know how or where the function is defined.
To write a forward declaration for a function, we use a declaration statement called a function prototype. The function prototype consists of the function’s return type, name, parameters, but no function body (the curly braces and everything in between them), terminated with a semicolon.
Here’s a function prototype for the add function:
1 |
int add(int x, int y); // function prototype includes return type, name, parameters, and semicolon. No function body! |
Now, here’s our original program that didn’t compile, using a function prototype as a forward declaration for function add:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int add(int x, int y); // forward declaration of add() (using a function prototype) int main() { std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n'; // this works because we forward declared add() above return 0; } int add(int x, int y) // even though the body of add() isn't defined until here { return x + y; } |
Now when the compiler reaches the call to add in main, it will know what add looks like (a function that takes two integer parameters and returns an integer), and it won’t complain.
It is worth noting that function prototypes do not need to specify the names of the parameters. In the above code, you can also forward declare your function like this:
1 |
int add(int, int); // valid function prototype |
However, we prefer to name our parameters (using the same names as the actual function), because it allows you to understand what the function parameters are just by looking at the prototype. Otherwise, you’ll have to locate the function definition.
Best practice
When defining function prototypes, keep the parameter names. You can easily create forward declarations by using copy/paste on your function declaration. Don’t forget the semicolon on the end.
Forgetting the function body
New programmers often wonder what happens if they forward declare a function but do not define it.
The answer is: it depends. If a forward declaration is made, but the function is never called, the program will compile and run fine. However, if a forward declaration is made and the function is called, but the program never defines the function, the program will compile okay, but the linker will complain that it can’t resolve the function call.
Consider the following program:
1 2 3 4 5 6 7 8 9 10 11 |
#include <iostream> int add(int x, int y); // forward declaration of add() using function prototype int main() { std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n'; return 0; } // note: No definition for function add |
In this program, we forward declare add, and we call add, but we never define add anywhere. When we try and compile this program, Visual Studio produces the following message:
Compiling... add.cpp Linking... add.obj : error LNK2001: unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z) add.exe : fatal error LNK1120: 1 unresolved externals
As you can see, the program compiled okay, but it failed at the link stage because int add(int, int) was never defined.
Other types of forward declarations
Forward declarations are most often used with functions. However, forward declarations can also be used with other identifiers in C++, such as variables and user-defined types. Variables and user-defined types have a different syntax for forward declaration, so we’ll cover these in future lessons.
Declarations vs. definitions
In C++, you’ll often hear the words “declaration” and “definition” used, often interchangeably. What do they mean? You now have enough of a framework to understand the difference between the two.
A definition actually implements (for functions or types) or instantiates (for variables) the identifier. Here are some examples of definitions:
1 2 3 4 5 6 |
int add(int x, int y) // implements function add() { int z{ x + y }; // instantiates variable z return z; } |
A definition is needed to satisfy the linker. If you use an identifier without providing a definition, the linker will error.
The one definition rule (or ODR for short) is a well-known rule in C++. The ODR has three parts:
- Within a given file, a function, object, type, or template can only have one definition.
- Within a given program, an object or normal function can only have one definition. This distinction is made because programs can have more than one file (we’ll cover this in the next lesson).
- Types, templates, inline functions, and variables are allowed to have identical definitions in different files. We haven’t covered what most of these things are yet, so don’t worry about this for now -- we’ll bring it back up when it’s relevant.
Violating part 1 of the ODR will cause the compiler to issue a redefinition error. Violating ODR part 2 will likely cause the linker to issue a redefinition error. Violating ODR part 3 will cause undefined behavior.
Here’s an example of a violation of part 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
int add(int x, int y) { return x + y; } int add(int x, int y) // violation of ODR, we've already defined function add { return x + y; } int main() { int x; int x; // violation of ODR, we've already defined x } |
Because the above program violates ODR part 1, this causes the Visual Studio compiler to issue the following compile errors:
project3.cpp(9): error C2084: function 'int add(int,int)' already has a body project3.cpp(3): note: see previous definition of 'add' project3.cpp(16): error C2086: 'int x': redefinition project3.cpp(15): note: see declaration of 'x'
For advanced readers
Functions that share an identifier but have different parameters are considered to be distinct functions. We discuss this further in lesson 10.7 -- Function overloading
A declaration is a statement that tells the compiler about the existence of an identifier and its type information. Here are some examples of declarations:
1 2 |
int add(int x, int y); // tells the compiler about a function named "add" that takes two int parameters and returns an int. No body! int x; // tells the compiler about an integer variable named x |
A declaration is all that is needed to satisfy the compiler. This is why we can use a forward declaration to tell the compiler about an identifier that isn’t actually defined until later.
In C++, all definitions also serve as declarations. This is why int x appears in our examples for both definitions and declarations. Since int x is a definition, it’s a declaration too. In most cases, a definition serves our purposes, as it satisfies both the compiler and linker. We only need to provide an explicit declaration when we want to use an identifier before it has been defined.
While it is true that all definitions are declarations, the converse is not true: all declarations are not definitions. An example of this is the function prototype -- it satisfies the compiler, but not the linker. These declarations that aren’t definitions are called pure declarations. Other types of pure declarations include forward declarations for variables and type declarations (you will encounter these in future lessons, no need to worry about them now).
The ODR doesn’t apply to pure declarations (it’s the one definition rule, not the one declaration rule), so you can have as many pure declarations for an identifier as you desire (although having more than one is redundant).
Author's note
In common language, the term “declaration” is typically used to mean “a pure declaration”, and “definition” is used to mean “a definition that also serves as a declaration”. Thus, we’d typically call int x; a definition, even though it is both a definition and a declaration.
Quiz time
Question #4
Write the function prototype for this function (use the preferred form with names):
1 2 3 4 |
int doMath(int first, int second, int third, int fourth) { return first + second * third / fourth; } |
Question #5
For each of the following programs, state whether they fail to compile, fail to link, fail both, or compile and link successfully. If you are not sure, try compiling them!
a)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int add(int x, int y); int main() { std::cout << "3 + 4 + 5 = " << add(3, 4, 5) << '\n'; return 0; } int add(int x, int y) { return x + y; } |
b)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int add(int x, int y); int main() { std::cout << "3 + 4 + 5 = " << add(3, 4, 5) << '\n'; return 0; } int add(int x, int y, int z) { return x + y + z; } |
c)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int add(int x, int y); int main() { std::cout << "3 + 4 + 5 = " << add(3, 4) << '\n'; return 0; } int add(int x, int y, int z) { return x + y + z; } |
d)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int add(int x, int y, int z); int main() { std::cout << "3 + 4 + 5 = " << add(3, 4, 5) << '\n'; return 0; } int add(int x, int y, int z) { return x + y + z; } |
![]() |
![]() |
![]() |
Hello, I have a task in uni with algorithms efficiency and while doing selection sort a ran into weird problem with forward declarations.
I can't forward declare my selection sort, because compiler doesn't know that MyArray class exist, but if I put MyArray class before forward declarations, MyArray class doesn't know that getRandomNumber function exist.
How should i rewrite my code to have correct sructure?
Also not related, but maybe someone will help, is there a way to override C++ array class like in C# int this[int index] {get; } so that i could use array[] sintax for my new array class?
Hi KugisMugis!
> is there a way to override C++ array class like in C#
Have a look at lesson 9.8 (Overloading the subscript operator)
This is easily resolved by moving the forward declaration for selectionSort() after the definition of class MyArray.
Dear Teacher, please let me point out o typo. In section "Declarations vs. definitions" paragraph: "You can only have ..." you say: "... having more than than one definition ...". One "than" is enough. Regards.
Fixed. Thanks for pointing that out.
I'm a little bit confused about forward declaring with a function prototype. Does it only declare the existence of the function or does it also let the compiler know how to use the function body. It must be the latter if main() is able to use add().
Hi Benedikt!
The forward declaration just tell the compiler "this function is somewhere, keep looking for it". You can use it in @main, because all @main needs to know is the function name/return type/parameter types. The forward declaration contains all these information.
But how is it able to fully use add() if the actual adding ( return x + y ) is happening in the function body?
It doesn't matter if you defined @add above or below @main, the final program will look the same in both cases.
When generating @main your compiler doesn't need to know what @add does, it only needs to know which parameters @add needs so it can generate a function call.
At some point your compiler generated @add and it knows where it is.
When execution reaches the @add call in @main, your computer will stop executing code in @main and jump to @add. When it's done executing code in @add it will return to @main and keep going.
Analogy:
You're sitting an an office and you want to buy a coffee.
You know you need $1 and you know there's a coffee machine somewhere.
You go looking for a coffee machine and find one.
You throw in $1, wait for your coffee and walk back to your office.
Office - @main
Coffee machine - @add
$1 - Parameters
Coffee - Return type
You - The current point of execution
I hope this helped more than it confused, I gave it several tries but all turned out too complicated. If this didn't help you'll have to wait for someone else.
I understand now. I was confusing compiling with execution. Thanks for your help :)
Yup. In short, the forward declaration helps the compiler do the syntax checking. But it's the linker that connects the function call to the actual function definition (which could be in main or anywhere else).
is your full name Alex Allain?
Nope.
Its little bit confusing to understand forward declaration and function prototype..
Function prototype as you said it will have function’s return type, name, parameters, but no function body (the part between the curly braces).
I understood this well sir..
in case of forward declaration it is confusing for me...
According to my assumption forward declaration means function is existing there..
For the function statement description you are saying it as function prototype..
I assumed it as like this..
If i am wrong correct me sir..
A function prototype serves as a forward declaration. The forward declaration tells the compiler that a function exists (and how to ensure calls to that function are correct) without having seen the function definition yet.
During a different project I was working on I by mistake ran into this situation where I had forward declared a function using a header file, but forward declared it with the wrong return type, (int instead of double, which was what I had later defined my function's return type to be in a separate file). The error that occured though perpelexed me. When I ran the program and came to the point where my main function called the incorrectly forward-declared function, the function returned an interesting value... What I assumed to be a random spot in memory which changed with every other run.
Here's an example code that illustrates the same thing. My main function would look like this:
And my "add.h" would look like this:
And then a separate add file would look like this:
And the output of this program would be some random number. (In my case something like 834281) Why is this? Could someone explain what's happening?
From within main(), the compiler would assume add(5, 6) was a valid call to int add(double, double), so the program should compile fine (it's syntactically valid). However, when the linker goes to link the program together, it should discover that int add(double, double) was never defined anywhere, and it should issue a fatal error.
Visual Studio 2017 gives this error:
Line Severity Code Description Project File Suppression State
1 Error LNK2001 unresolved external symbol "int __cdecl add(double,double)" (?add@@YAHNN@Z) ConsoleApplication1 C:\Users\xxx\Documents\Visual Studio 2017\Projects\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.obj
Hey,
Often in this article you use the word "identifier". What exactly is an "identifier" or can you just point me to another chapter that talks about it?
Thanks.
This is the perfect kind of thing to look up in the site index. See http://www.learncpp.com/learn-c-site-index/#Identifier
Hi Alex,
I think that how "linker" and "compiler" work could have been described clearer in this chapter, at least for the purpose of this topic. There are few cryptic lines about them here and there, but for me, not enough to being included in the Quiz questions without the support of some more examples.
In fact, I had to use Ctrl+F to find them and read again the sentences in which are included, but still I am unsure what the two require to work properly or fail.
Much respect and appreciation for your hard work on this website. Thanks and keep it on!
Thanks, I'll see if I can figure out how to make it clearer. I appreciate the feedback.
Hey! I was wondering if you did something for explaining linker and computer function separately
Not yet. It's on my to do list.
What is the use of function prototype?
Can't we just directly write the function, instead of the prototype?
It will be time saving!
thank you
The function prototype informs the compiler what a function looks like, so that if the function is called before the compiler has seen the full definition of the function, it can validate whether the function call is correct.
Most often, this is used when calling functions that are defined in another file altogether.
"Most often, this is used when calling functions that are defined in another file altogether."
So, we can use a function which is in a different file, but we have to forward declare it? Thanks Alex for all the effort!
Yes. If you don't forward declare the function in the other file, the compiler won't know that the identifier (function's name) is valid or how to do type checking.
Can you explain what's the difference between not compiling and not linking please. :)
I don't understand the context of the question.
In Solution 5, you indicate the problem is the difference in number of parameters between the function itself and its declaration. If I add a parameter to the declaration, "int z" so it matches the number of parameter in the function, the code still won't compile.
If I change the main function from
to
passing a third argument, "5", to the function, the code compiles.
I want some help to understand this
can you just explain better to me?
Sure. Function add() is defined to take two parameters, which we're calling x and y (they have to have some name, so we can differentiate them inside the function). When we call function add(), we'll pass it two arguments -- the first argument will be associated with x, and the second argument will be associated with y. So when we call add(3, 4), the value of 3 is passed to x, and the value of 4 is passed to y.
Is that second error message really redundant though? I understand that it's a little confusing, but it seems to make logical sense to me. When the compiler first sees "add", it recognizes that add is undefined and complains, but at that point add IS defined as an "unknown identifier". So, when the compiler gets to line 9, now the compiler complains that it has already defined add as an unknown identifier, so it doesn't want to redefine it.
I'm not complaining that this error message got removed or anything, and I understand that it is confusing... It just seems to me that the message DOES make sense in a roundabout sort of way, and it also seems to me to be technically correct. I am also not suggesting that you should rewrite any of this page, I just wanted to get confirmation from you on whether or not I'm thinking about this in the right way. In any case, thank you again for all your hard work on this course, it has been extremely useful for me! You're the man Alex!
I'm not sure I really understand why older versions of Visual Studio defined an unknown identifier as "unknown identifier" rather than just leaving it undefined. It makes more sense to leave it undefined so that when it was defined it doesn't cause a redefinition error (because it's not a redefinition, it's the actual definition).
I tried experimenting with function prototypes, and I found this a bit weird. I know how you said that all function prototypes need to do is tell the return type and parameters, but you can just use different identifiers for the parameters and retain the parameters' datatypes.
Is this worth a comment?
I updated the lesson to note that you should use the same parameter names for both the actual function and prototype (even though C++ lets you do otherwise). For prototype purposes, the compiler ignores the names, so they're really there just for the benefit of the programmer.
Hi Alex,
could you help me understand better about declaring and defining?
does this define the variable x as well as declare it?
Is defining different from instantiating?
would this also be true?
thanks!
This declares and defines variable x. It also has the effect of causing x to be instantiated.
Assuming these are meant to be separate questions (not sequential statements in a program), both do the same thing: declare, define, and instantiate variable x. The former one also initializes x, whereas the latter one does not.
My dear c++ Teacher,
Please let me ask that I can not understand:
For program forgetting the function body, Code:Blocks's Build massages among others are:
undefined reference to 'add(int, int)'
error: 1d returned 1 exit status
=== Build failed: 2 error(s), etc.
I understand there is one error: undefined reference to 'add(int, int)'.
What is second error?
No idea. I only see one error there.
My dear c++ Teacher,
Please let me say my suspicion.
Code::Blocks by "2 errors" mean one error in two files: add.obj and add.exe, as visual studio 2005 express's message. Do you think so?
By the way let me say my answer to quizzes 3 and 4:
The compiler will complain that the add() called in main() does not have the same number of ARGUMENTS as the number of PARAMETERS of the one that was forward declared. Is it correct?
With regards and friendship.
I have no idea about the 2 errors issue.
For the quiz, yes, you are correct.
My dear c++ Teacher,
Please let me say what I can not understand. You say:
"A definition actually implements or instantiates (causes memory to be allocated for) the identifier"
My understanding is that variable declaration causes memory to be allocated for the identifier.
With regards and friendship.
Incorrect. With variables, most of the time, the variable definition serves as the declaration as well. For example:
This statement is both a declaration (it tells the compiler about a variable named x of type int) and a definition (when executed it causes the compiler to allocate memory).
It's possible to have variable declaration-only statements:
This tells the compiler that there is a variable named x, but that the variable already exists somewhere else (e.g. in another file), so it should not allocate memory for it. We cover this in chapter 4.
My dear c++ Teacher,
Please accept my many thanks for you replied my message. My knowledge so far is that compiler does not involve in execution. Executable file allocates memory.
With regards and friendship.
When I say, "the compiler allocates memory", I'm speaking imprecisely to mean, "The compiler will create a statement that when executed will cause memory to be allocated".
Hi Alex,
You listed the following as a reason for forward declarations:
"If function A calls function B, and function B calls function A, then there’s no way to order the functions in a way that they will both be happy. If you define A first, the compiler will complain it doesn’t know what B is. If you define B first, the compiler will complain that it doesn’t know what A is."
However, how can two functions ever call each other without producing a continuous repeating cycle. For example:
I’d be ever so grateful if you could provide me with an example where a cycle doesn’t form when two functions call each other. This would better my understanding.
Many thanks Alex, this site has helped me massively.
Alex
In short, the answer is that one or both of your functions can have code that prevents the other function from being called if some other condition is true.
Here's a short example with a single function that you can extrapolate to the two function case:
We cover this in more detail in the lessons in chapter 7 talking about recursion.
The function call of add is on line 5.....not 6. And add is defined at line 9 not 10 -(3rd paragraph). First example.
Great website !!! I'm really finding it useful and enjoying it.
Thanks
Val
Thanks for visiting. Typo fixed!
Great resource. Not sure if the above mentioned typo was fixed.
Fixed for reals this time.
My dear c++ Teacher,
Please comment following program. It works fine.
With regards and friendship.
I'm not sure what you want me to comment on, other than to say this program is hard to read because the function definitions are on the same line as the function prototypes.
My dear c++ Teacher,
Please let me ask a clarification:
Do you mean: main, f1, and f2, bodies are on the same line as the their types, names and parameters?
My understanding is that f1 and f2 prototypes are above main() function, and their definitions below it.
I mean the function bodies are on the same line as the function prototype. E.g. this:
Instead of this:
My dear c++ Teacher,
Please let me again ask you:
Is it correct that "function prototype is a forward declaration for a function"?
With regards and friendship.
Yes
My dear c++ Teacher,
Please let me this question:
In subsection "Declarations vs. definitions", 3rd paragraph, you state:
"A declaration is a statement that defines an identifier (variable or function name) and its type.". Do you mean "... that declares an identifier ..."?
With regards and friendship.
Poor wording on my part. I changed "defines" to "announces". A declaration announces an identifier and its type. A definition instantiates or implements it.
My dear c++ Teacher,
Please let me point out that in first paragraph you state:
"The reason this program doesn’t compile is because the compiler reads files sequentially".
Apparently you mean: "reads lines sequentially".
Also in next sentence you state: "When the compiler reaches the function call to add() on line 6 of main(),".
In PC I use, function call to add() is on line 5.
With regards and friendship.
It reads both files sequentially and the lines in the files sequentially. Your line numbers may vary slightly depending on whitespacing and whether you #include "stdafx.h" or not.
My dear c++ Teacher,
Please let me point out that in "Function prototypes and forward declaration of functions" subsection, under program, you state:
"Now when the compiler reaches add() in main, it will know what add() looks like (a function that takes two integer parameters and returns an integer), and it won’t complain."
When compiler reaches add(), in main(), not only will know what add() looks like, but also will execute it, although it is AFTER main().
With regards and friendship.
No, that isn't quite right. Remember, the compiler just does syntax checking -- the function isn't actually executed until runtime.
My dear c++ Teacher,
Please let me say that I am forced to use compilers online that compile, link, and run, altogether, by one click. One exception is
https://www.tutorialspoint.com/compile_cpp_online.php
that compiles (and apparently links) by clicking on "Compile", and executes by clicking on "Execute".
With regards and friendship.
Maybe u should provide code tags for the second solution.
Maybe I should! Done, thanks for the suggestion.
You can tell the time and effort they put into this tutorial is outstanding! Great job, and very helpful :)
I'm a bit confused about the relation between the terms "variable definition" and "variable instantiation".
Is my understanding of "definition" correct?
"Definition is a more general term covering both the implementation (of a function for example) and the instantiation (which actually allocates some memory) of the identifier"
A definition is a general term for the code that uniquely specifies how an identifier is implemented. It's what the linker needs to work.
For variables a definition causes an instantiation. For functions and types, the definition causes those things to become callable/usable.
#include <iostream>
using namespace std;
int add(int x, int y);
int main()
{
int a , b;
cout<<add(3,4)<<endl;
cin>> a >> b >> endl;
cout<<add(a,b)<<endl;
return 0;
}
int add(int x , int y)
{
return x+y;
}
I tried adding cin fucntion so that , a value can be added at the output itself. why isn't it working?
what is wrong with the prog?
Usind Dev c++
The compiler should be telling you what's wrong.
But in case you can't decode the message, you can't cin >> endl. Remove the >> endl.
""Now, here’s our original program that didn’t compile, using a function prototype as a forward declaration for function add():
#include <iostream>
int add(int x, int y); // forward declaration of add() (using a function prototype)
int main()
{
using namespace std;
cout << "The sum of 3 and 4 is: " << add(3, 4) << endl; // this works because we forward declared add() above
return 0;
}
int add(int x, int y) // even though the body of add() isn't defined until here
{
return x + y;
}""
I used the same example, but they give me an error in "int main()" and they say that it is undefined. I am confused !!!
This is compiling fine for me. What exactly is your compiler saying is undefined? Function add()?
"It is worth noting that function", "noting" should be "nothing". :)
No, it's correct as written. Noting as in "taking a note".
"It is worth nothing that function" cried Father. "I raised him from a babe, tried to teach him right from wrong, pass-by-const-reference rather than by-value, gave him a blueprint, a prototype to work form, and what does he give me in return? Nothing"
(I think I've had too much coffee ... and sugar)