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; } |
![]() |
![]() |
![]() |
So basically:
- A definition makes the identifier (so in the case of a variable named x, it would be instantiated)
- A decleration just says what an identifier is (so it would say that x is a variable) (and a function prototype is a decleration because it says that there is a function called x but it doesn't actually make x)
I got a bit confused so can you check if i'm correct :P
Also, why do you call things like functions and variables "identifiers"? It's like calling humans "names", it doesn't make sense. Have I missed something in the lesson about naming identifiers?
The term "identifier" in programming is basically synonymous with with the word "name" in common usage. So when we talk about identifiers, we're talking about the names of things (functions, variables, etc...). We talk about naming variables and functions in one of the previous lessons.
For example:
i is the identifier (name) of this variable. When we talk about this variable specifically, we use "i". When we talk about variable names generically, we use "identifier".
Yeah, that's basically the right idea. Put another way, a declaration announces an identifier's name and type so other code can reference it. A definition actually causes memory (for a variable) or code (for a function) to be created.
I think that the real answer to question 2 is
int doMath(int first, int second, int third, int fourth)
which is the function prototype. Another problem is that the title of Question 3 is at the end of Question 2.
Thanks!
Quiz answer 6. You say "The function call to add() matches the prototype [...], the the implemented function also matches."
The the that is redundant needs to go.
The the extra the has been retired. :)
Thanks!
@Alex
Its interesting to see that the following code both compiles and links.
(GCC 4.8.1 using `-std=c++11 -Wall -pedantic` as options)
If I pass three arguments to add() in main() then the add() with three parameters is getting executed.
Similar is the case with the print().
I agree that having two functions with the same identifier in the same file is not a good idea.
Depending on the number of parameters and return type, I think, the linker resolves the appropriate function.
Anything that you want to add to it?
Also, since redefinition is not allowed, how come it is not the case with add()?
Are the two different add() functions treated as different functions?
Thanks.
PS: Thanks for creating LearnCpp!
Also I used backslash to escape the quotes within quotes in the code on lines 20 and 21 but the 'code' tags removed them. I can't even write them here.
Yes, what you're experiencing is called "function overloading". I talk more about this in lesson 7.6 -- Function overloading.
In short, a function's uniqueness is determined not only by its name, but also by the number and type of parameters (and a few other things, such as what class it's in and whether it is const). This means you can have functions with the same name, so long as they have different numbers and/or types of parameters. In general, this is a good thing, particularly when we have functions that need to have different (but similar) behaviors based on the number or types of parameters.
Thanks. That helped.
@ALEX Your tutorial awesome but I am having a confusion b/w linking and compiling error...
linking error will occur when there is a disparity between the number of data sent from main function and the number of params in the receiving function (or the prototype)& compiler error will occur when there is a disparity between the number of parameters in the fwd declaration and the function...A program runs sequentially so Question 3 and 4 and 5 are linking errors...Please correct me....
Thanx
No.
A compiler error will occur when the compiler detects a syntax error, a naming collision, a mismatch in parameters, a call to an undefined function, etc...
A linker error will occur when a function has been declared and called but not defined.
<<Really ,i like this site ,>>
can anyone tell me that what is most important topic in c++?
What is the most important part of a car?
Everything. :D
And to Pradeep: Everything also lol. It's all in harmony and actually depends on the type of problem you want a solution (program) for; if you wanna code a program that prints the sum of some numbers you input, then you don't need to dive deep in the language... But if you're making something heavy that reads values from a file or a block storage system or even from a network (I dunno if that's even possible) then do hardcore operations including pointers and memory stuff (that I generally find hard :D) then you need a lot of knowledge. There's no limit bro.
Most important? Write code every day. As you learn you need to establish a clear, consistent mental model of how the various elements in C++ function and then write yourself small test programs to validate that model. As you develop you need to develop the skills to create and debug solutions. Writing code to solve new problems, and going through the process of framing the solution and identifying and resolving the issues with the solution. As your project become more complex you'll need to be able to assure their correctness. Write code to test your components.
This is a craft, you have to practice it.
I am just learning this stuff and you guys are doing an awesome job. You have thrown in a term I haven't seen yet... "linker". Normally when you list a new term you bold it and define it... not this time. Help me out?
The linker is talked about back in lesson 0.4 -- Introduction to development.
Just to say the site really is very helpful. Keep up the good work.
Hi, Alex. Great tutorial. Really enjoying it.
Just one question about the declarations vs, definitions section above. Why in the first instance(definition) do you say with int x it "instantiates an integer variable named x", ie. memory is allocated for it, but in the second instance(declaration) you say "declares an integer variable named x". Didn't you say at the start of the tutorial that when you write "int x" memory is allocated. So in other words in this case memory should be allocated in both instances and hence both are instantiated. Or did you just add them in both instances to show that int x can be a definition AND a declaration, and hence is initiated(memory allocated to it) in both cases? I read through the comments and actually saw that you replied to Matthew saying int x is both a declaration and definition. I just want to be sure that this was what you wanted to show in your above examples to start with.
Thanks :)
Yes, "int x" is both a declaration (telling the compiler that x is an integer variable) AND a definition (allocating memory for integer variable x).
Later on, when we cover forward declarations of variables, you'll learn it's possible to declare variable x without instantiating it.
Alright, got it. Thank you :)
So essentially, a forward declaration behaves like a variable for a function whose definition has not yet sequentially appeared, (similarly to how X can be declared as a variable without being given a value) and the function prototype syntax distinguishes this "variable" as a function?
Using the word variable is confusing here, because functions aren't variables.
A forward declaration simply allows us to tell the compiler that an object (a variable, a function, a type, etc...) exists but will be defined later. This allows us to use an object that may be defined later in the file, or perhaps in another file altogether.
For functions, a forward declaration is done via a function prototype.
Can you all please help??
when i saw the first question i couldn't answer it because the question was :
What’s the difference between a function prototype and a forward declaration?
and when i saw the answer i saw "A function prototype can be used to forward declare a function" isn't that mean that prototype is forward declaration or a type of it?
please replay fast because i cant really continue if i didn't understand something. and by the way thx alex for this awesome guide i really learned alot :).
and can you tell me please the Meaning of definition because i don't understand how a function can be defined.
A declaration tells the compiler that an identifier exists. A definition provides the compiler with enough information to instantiate or execute something.
In the case of a function, a function declaration is just the prototype. It's enough to tell the compiler that the function exists, but not enough to actually execute it. A function definition includes the prototype and the function body. A function definition is enough for the compiler to translate the function into machine language, so it can be executed.
A function prototype declares a function's name, return type, and parameters. It does not include the function body.
A forward declaration tells the compiler that something exists before it is actually defined.
For functions, a function prototype serves as a forward declaration.
For other types of objects (e.g. user-defined types) they have a different syntax for doing forward declarations.
Make sense?
Yeah that makes sense.
Thanks for replaying.
Hey Alex. Is there a way to tell the difference between a compiler-specific and linker-specific error in Microsoft Visual Studio Express 2013 for Windows Desktop?
If you look at the error codes Visual Studio provides when compiling, linker errors usually start with LNK, whereas compiler errors usually start with C.
Ok, thanks.
Okay...compiler executes program sequentially but starts execution from top of main (). If execution starts from top of main(), compiler should know about add() (because it's being called in main), but as written above, it doesn't in this program:
If add () is defined above main(), the program compiles fine. Does that mean compiler can't jump below main () to find a function's definition. I know that's stupid, but I proud myself for being stupid.
Remember that the compiler compiles the program before execution can start. So for purpose of compiling a program, execution doesn't matter.
When the compiler compiles a file, it does so sequentially, from top to bottom. In your example, when it gets to the call for add(3,4), it checks its internal database to see if it's seen a definition for add(3,4) and says, "nope!". Then it gives you an error.
There are a few ways to get around this:
1) Define add() above main()
2) Use a forward declaration, which tells the compiler "I promise I'll define this later" (passing the buck to the linker)
So basically, the compiler can't jump below main() to find a function definition while compiling. This is an intentional limitation because the alternative (having the compiler look for a definition) would be both inefficient and complicated. Especially if add() used a definition the compiler hadn't seen yet. In the worst case, that could exponentially increase your compile times.
ohh yes .thankx i got it
#include<iostream>
int add(int x, int y)
{
}
int main(){
std::cout<<3+4<<add;
return 0;
}
why the output is 71 here?
Similar answer to the above. 3+4 = 7, so that's where the 7 comes from. Instead of calling function add(), you're printing the memory address that function add lives at. Why this is printing a 1 I have no idea.
In your code above, "add" should be "add(3,4)" or something.
what is the difference between
#include<iostream.h>
and
#include"iostream.h"
This is covered in section 1.9 -- Header files.
I'm loving these tutorials!
I found a grammatical error - the first I have seen in all these tutorials!
"A declaration is an statement"
should be
"A declaration is a statement"
Also, "a integer" should be "an integer" in the code:
Not trying to be annoying - just trying to keep your fantastic tutorials flawless!
Thanks for pointing those typos out. They're fixed now.
#include <iostream>
int add(int x, int y)
{
return x + y;
}
int main()
{
using namespace std;
cout << "The sum of 3 and 4 is: " << add<<
(3, 4) << endl;
return 0;
}
when i type this program with <<add<<
(3,4)
like above why does it give an output of 14 instead of some error.
if such a thing occurs in a large program how can it be resolved.How can i highlight the code the [/ ] brackets aren't helping?
It shouldn't give an output of 14, it should give something like 010011724. cout << add will send the address of function add to cout, which prints "01001172" (or whatever address it is for you). (3,4) evaluates to 4, so it prints as 4.
Generally if this were to occur in a large program, you'd note that the output was wrong and then find the line that was incorrect (possibly with the assistance of the debugger). Then you'd hopefully note that your statement should be cout << add(3,4) instead of cout << add << (3,4) and fix it.
thank you for the reply and also for the wonderful tutorial.
why is that variable declaration cause memory allocation and forward declaration does not for variables?
Variable declarations are also variable definitions. We use these to tell the compiler that we need a variable to be allocated in memory at this point in the code.
Forward declarations are pure declarations (not definitions), so no memory needs to be allocated for them. Forward declarations just let the compiler know that something exists. They don't allocate memory for that thing.
You guys are the best! Keep up the great work and the updates!
In your page 1.7 forward declaration, when you talked about declaration and definition,
you gave examples as int x; for both declaration and definition?
Is this correct? Declaration is something like x of type int exists and definition when memory comes in picture. Please elaborate author. Muchas Gracias in advance. Great tutorial.
Actually I got it. Pure declarations and most definitions are declarations too! Sorry. I typed the comment premature and did not read the entire page.
I declared a function two times with same name,number of arguments, and data type but the compiler didn't give an error.Why?
Declaring an identifier more than once is not illegal. It's just redundant.
Note that you can only define your function once. If you try to define it more than once, your compiler will complain.
There wouldn't happen to be video tutorials, would there?
Nope.
Second question of the quiz in 1.7: "DoMath" should preferably and according to 1.4c be named "doMath"... Very nice tutorial and very understandable as well. Thanks so much Alex.
Yup, it was out of compliance with best practices, and has been updated. Thanks for the note.
A function prototype is declaration statement that tells the compiler what a function’s return type is, what the name of the function is, and what the types of the function parameters are. A function prototype can be used to forward declare a function. A forward declaration tells the compiler about the existence of a function (or other type of object) in advance of where it is implemented.
- I dont think there is a difference in terms of its usage. Declaring a prototype is the act of forward declaring.
Handy information! A few things I was wondering about, though. And then I tested them because I realized I could answer my own questions. Huh. Well here's the answers in case anyone else is interested, then. =P
#1: Does the int add(x, y) always have to be NAMED add(x, y)?
I've tested and found I can call it addmoose(x, y) without issue.
#2: Does the "add" part NEED to be part of it?
moose(x, y) works just fine, apparently the "add" part is just there for good housekeeping and labeling.
#3: can I have multiple functions named the same thing with different parameters?
Yes and no I found out. I tried messing around with an add and a multiply function to test where the limits were, this is what I came up with:
moose(x, y)
moose(Na, Nb)
Did not work. As far as it was concerned, the x/y and Na/Nb were identical; what they're called doesn't matter, only the number of parameters.
moose(x, y)
moose(Na, Nb, Nc)
Did work. It doesn't seem to matter that you call it the same thing, so long as it can differentiate between moose(2 parameters) and moose(3 parameters). No, I don't know why I used moose.
#4: Is it a good idea to name functions the same thing?
Depends on the situation, I think. I guess if you're multiplying several different things, you could call several functions multiply and just alter the number of parameters. Since they're reusable in different contexts, and multiplying 3 parameters tends to work exactly the same no matter which parameter is being multiplied, so long as you have 3 of them, I suppose it's not that big of a deal.
On the other hand, it's handy to name more complex functions to be clear about exactly what it is they're supposed to do. add(2 parameters) is pretty obvious that it adds two parameters together, so isn't exactly a big deal if you have add(x, y) and add(x, y, z).
If you're trying something more complex, such as... pft, I dunno, something like "F = (D* (((E+Y)*(X/N)) *0.01) / (1+0.01* ((E+Y)*(X/N)))", then you might want to stick to a somewhat more descriptive title for the function. You COULD reuse totalNonsense(D, E, X, Y, N) with totalNonsense(X, Y, Z), but I wouldn't particularly suggest it due to issues of confusion.
Anyway, just the random stuff I came up with when trying to figure out some exceptions to the rules. =3
Regarding your point #3, C++ supports a concept called "function overloading", whereby you can have multiple functions with the same name so long as no two functions have the same number of parameters of the same type in the same order. I tackle this topic in more detail in section 7.6 -- Function overloading.
You'll note the following does compile (we haven't introduced double yet, but it's a numeric data type like int):
Regarding your point 4: as long as the use of the name is intuitive, there's no problem using the same function name for more than one thing.
Hi Alex,
Really, I am happy and admired about this tutorial. One of the best online tutorial I have ever seen. My question is do you have any idea about BODMAS Theorem. If you know can you please share with us ??
Hi,
I don't think
is a definition.
int x; is a definition (and a declaration). A definition defines how something is implemented -- in the case of variables, it's probably more intuitive to say it instantiates the variable (causes memory to be allocated for it).
One way to tell it's a definition is to duplicate the line and see if the compiler complains (remember, things can only have one definition.
If you do this:
The compiler will complain.
Although we haven't covered it yet, it is possible to forward declare variables. In that case, the forward declaration is a declaration only (and does not allocate memory -- it just tells the compiler that a variable exists, but it's defined elsewhere).
I've updated the lesson text to be more clear about what definition means for variables.
Thanks!
you still don't want to make a class for matlab or fortran?:)
Nope. :)
Can i just make a function call like : int add(int x, int y); before the line of add (3, 4) ?
You can make a call add(x,y);, providing x and y have been initialized before.