C++ link errors

What does it mean when you compile a C++ program and get no errors, but then you debug and get link errors? Is it a problem with the code or the compiler? How the heck do I fix it?

Here’s the error message if that gives any clues:

Linking…
class.obj : error LNK2001: unresolved external symbol “int __cdecl qualityPoints(int)” (?qualityPoints@@YAHH@Z)
Debug/homework.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

homework.exe - 2 error(s), 0 warning(s)

It means that you have these symbols - i.e., the function name/prototype, properly defined in the .h files you included (so it compiles properly), but you don’t have the .obj or .lib files for that function to be executed included in your project. And if the function is expected to be in a .dll, you don’t have that dll name listed in the exports section of your .def file.

Tell me, are you by any chance mixing both .cpp files and .c files? Is the function qualityPoints(int) to be found in a .c file?

Or perhaps is the function qualityPoints(int) to be found in a DLL?

Is there a qualityPoints function anywhere in the code? Is it accepting only one parameter and is that parameter an int?

Maybe it’s the lack of an extern “C” somewhere? i.e. the linker is expecting to see the function exported “C” style, without name mangling?

In my experience, Visual C++ has strange ways of locating source code during the link phase. This is how I fix most link errors:

Go to the Project menu, and choose Add To Project. Choose the .cpp file the function or class implementation (the one the linker is complaining about) in the dialog box and click OK. You should only insert the implementation file, not the header.

Check the Directories tab under the Options menu. Make sure the directory or directories your source files are in is listed. If necessary, add the directories by clicking on the … button and selecting the directory in the dialog box. This shouldn’t be necessary if all the files are in the same directory, though.

Also, try choosing Rebuild All from the Build menu.

Actually, it’s a programmer-created function–I’ve created it and called it in the same .cpp file, so it shouldn’t be having one of the problems above. Any other ideas??

Well, in general, most linking errors relate to something that has been left undefined (like a function that has been called, but not defined) or something that has been multiply-defined (again, functions, most often).

This also usually relates to things happening across multiple files, since same-file issues would usually be resolved during the compile stage (i.e. before linking occurs).

I find that linker errors are just as often (if not more) caused by incorrect compilation commands or setups as they are by problems in the coding.

You indicate that it’s a function you create and call in the same file. Care to show some of the code in question? That may help.

Also, is this a member function of a class? Or is it a plain stand-alone function.

One scenario that could cause this is if you have a member function declared in a class header file, then try to define that function in another file (even if in the same file you made the call) – but where the function definition doesn’t quite match up to the declaration exactly.

For instance, if I create a function prototype:

void Function(const int & x);

Then I define that function this way:

void Function(int & x)
{
// blah blah blah
}

The call may be matching up to the initial prototype, but the compiler may not see the above definition as matching the prototype (because the parameter list is slightly different – the definition doesn’t have the const) – so the “matching” function would be still considered undefined – and hence, a linker error.

(Note, this wouldn’t produce a compile stage error, because the first prototype does match the call, and all you need is “declare before use” for translation to object code).

Another more glaring possibility: you declared the function in the header file, and implemented it in the cpp file - but forgot the class name before the implementation! I’ve done this myself many times, and it will produce the error you gave.

e.g. in header



class CMyClass
{
   void foo(void);
}


in cpp:



void foo(void)
{
}


which should have been



void CMyClass:foo(void)
{
}


I know, I know - void CMyClass:**:**foo(void)

But in this case, the function is returning a value, so I shouldn’t do void, right?

Darren – that’s another possibility, but I find that this sort of error is usually caught by compilation (not linking), since normally, a member function will use some or all of the member data (or member functions) of the class. And in that case, the compiler would report an error about the variables that you used inside of such a function being undelcared:

class Thing
{

int Func();
int x; // member data

};

Definition, leaving out the class name and scope-resolution operator:

int Func()
{
x = x * 10;
return x;
}

When I compile this, I’ll get an error about x being undeclared.

In the instance that you have a member function that doesn’t use any other member of the class, then there won’t be any problems with this function (compiler will consider it a stand-alone), and it will reach the linking phase (and give the undefined function error for the call to the member function).

booklover – yes, if the function is returning a value, you should have a non-void return type.

Show us a small snippet of the code please.

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

int qualityPoints ( int );
int x;
int main()
{
int x;
cout<<"The student’s average is: "<<qualityPoints(x);
cout<<endl;
return 0;
}

int qualityPoints ( )
{
int y = x;
int qPoints;
cout << "Enter student’s average: ";
cin >> y;
if (y <= 100)
qPoints = 4;
if (y <= 89)
qPoints = 3;
if (y <= 79)
qPoints = 2;
if (y <= 69)
qPoints = 1;
if (y <= 59)
qPoints = 0;

return qPoints;
}

Linking…
class.obj : error LNK2001: unresolved external symbol “int __cdecl qualityPoints(int)” (?qualityPoints@@YAHH@Z)
Debug/homework.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

It looks like the implementation of the function qualityPoints() is not the same as the prototype. The prototype says the function takes a integer argument, where the implementation does not. The reason your function gets the value for x is because x is declared globally.

To fit it, removed the declaration for x just under the prototype, pass in the value of x as an argument to the function, and update the function implementation to have x as an argument.

You stated the existence of a function qualityPoints:

int qualityPoints ( int );

which promises that if you give it an int, it will do something, and return an int to the caller. You even use it in this intended way in main:

cout<<"The student’s average is: "<<qualityPoints(x);

However, the function itself is a different qualityPoints that takes no parameters and returns an int:

int qualityPoints ( )
{
//code
}
C++ allows for multiple functions by the same name as long as the parameters are different. So you’re saying the first qualityPoints exists, and try to use it, but you’re defining a different one. When the compiler tries to tie all this together at link time, main ends up trying to call a qualityPoints that doesn’t exist.

Presumably you meant:
int qualityPoints ( int )
{
//code
}

…but even this isn’t enough to fix your problem. You haven’t given the incoming parameter any sort of name. Although you’re not required to in a function prototype as you have above main:
int qualityPoints ( int );

you are expected to give the variable a name in qualityPoints when you actually define the function later on:
int qualityPoints ( int x )
{
//code
}
Note that this x has nothing to do with the x in main whatsoever, except for the specific call to qualityPoints wherein a copy of main’s x is made so that qualityPoints’s x has a value. Main’s x could be changed to q throughout main, and it would have no impact on the current behaviour of the program, even if you just made the recommeded fixes to qualityPoints. Passed parameters in C++ are copied from the variables you specify at the time of call into the temporary corresponding local parameter values inside the called functions.

And neither of these has anything to do with the global variable int x that you have just before the definition of main. The int x inside main hides the one outside of main so you are never changing the global variable. Presumably somewhere in your real code you’re reading a value into x. You have to be absolutely sure which x you’re reading into.

If you intend to pass parameters via the function parameter list, that’s fine. If you intend to pass parameters by stuffing them in global variables that’s fine. Just don’t mix the two and get horribly confused.

My recommendation, since I detest global variables: Get rid of the int x; above main. Give the integer parameter to qualityPoints a name even in the prototype above main, but also make sure the parameter list matches in the definition of qualityPoints after main.

Your prototype and implemenation differ. Make them match

change:
int qualityPoints ( int ); // prototype
to
int qualityPoints ( int PassedInt); // prototype

change
int qualityPoints ( ) // Implementation
to
int qualityPoints ( int PassedInt) // Implementation
then let
y = PassedInt;

Before the test, ask your professer to explain parameter passing in detail for you.

Amen to that, William. I teach C++, and prohibit students from using global variables (with the possible exception of constants) on all assignments.

booklover – when you build functions, keep in mind that the declaration always consists of a return type, a function name, and a parameter list (how many parameters, and their types). And when you define the function, you need to use the same return type, same name, and same parameter list, if you want it to be considered the same function. A function by the same name with a different parameter list is allowed – but it is a different function – this is a feature often called function overloading.

I’ve never formally taught (been tempted a couple of times). I’ve spent a truly… daft amount of time helping out students, contemporaries, and cohorts over the years in various languages, so I have some experience in the academic side of things. A great deal of my experience comes from work in the field too.

< rant >
I have never seen a situation where my first gut reaction with my current level of experience would say “Oh, this is best solved with a global variable.”

I fight tooth and nail around my own workplace and with any students who ask for my help to avoid and banish global variables.

They should be the exception, not the rule, and a rare exception at that.

< /rant >

Good on you, Monstre!

One of my favourite bits of evil in the past has been to give out some very short but truly hideous program written with global variables and have the victim convert it to a program that uses none – and then ask them which is easier to follow…

I even try, from time to time, to point out to people that within a C++ object, member variables are almost akin to globals within the context of that object… Data that is best instantaneously passed in and out of the methods being called should not be made member variables! The argument is far weaker, however.

It’s late, and I just started programming this semester too (C++ also), but to the other programmers here, is it me, or does that code look um… not so good?

That’s very tactful of you, Ian Fan. Yes, as I discovered once I finally fixed my link errors, that code is not so good. I’m planning on re-reading my textbook from chapter one this weekend.